audio_output_win_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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. 4 5#include <windows.h> 6#include <mmsystem.h> 7 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" 23 24using ::testing::_; 25using ::testing::AnyNumber; 26using ::testing::DoAll; 27using ::testing::Field; 28using ::testing::Invoke; 29using ::testing::InSequence; 30using ::testing::NiceMock; 31using ::testing::NotNull; 32using ::testing::Return; 33 34using base::win::ScopedCOMInitializer; 35 36namespace media { 37 38static const wchar_t kAudioFile1_16b_m_16K[] 39 = L"media\\test\\data\\sweep02_16b_mono_16KHz.raw"; 40 41// This class allows to find out if the callbacks are occurring as 42// expected and if any error has been reported. 43class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { 44 public: 45 explicit TestSourceBasic() 46 : callback_count_(0), 47 had_error_(0) { 48 } 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(); 56 } 57 virtual int OnMoreIOData(AudioBus* source, 58 AudioBus* dest, 59 AudioBuffersState buffers_state) { 60 NOTREACHED(); 61 return 0; 62 } 63 // AudioSourceCallback::OnError implementation: 64 virtual void OnError(AudioOutputStream* stream) { 65 ++had_error_; 66 } 67 // Returns how many times OnMoreData() has been called. 68 int callback_count() const { 69 return callback_count_; 70 } 71 // Returns how many times the OnError callback was called. 72 int had_error() const { 73 return had_error_; 74 } 75 76 void set_error(bool error) { 77 had_error_ += error ? 1 : 0; 78 } 79 80 private: 81 int callback_count_; 82 int had_error_; 83}; 84 85const int kMaxNumBuffers = 3; 86// Specializes TestSourceBasic to simulate a source that blocks for some time 87// in the OnMoreData callback. 88class 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) { 92 } 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_); 99 } 100 return audio_bus->frames(); 101 } 102 private: 103 int laggy_after_buffer_; 104 int lag_in_ms_; 105}; 106 107class 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)); 115 116 static int ClearData(AudioBus* audio_bus, AudioBuffersState buffers_state) { 117 audio_bus->Zero(); 118 return audio_bus->frames(); 119 } 120}; 121 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. 125class 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; 144 } 145 ~ReadOnlyMappedFile() { 146 if (start_) { 147 ::UnmapViewOfFile(start_); 148 ::CloseHandle(fmap_); 149 } 150 } 151 // Returns true if the file was successfully mapped. 152 bool is_valid() const { 153 return ((start_ > 0) && (size_ > 0)); 154 } 155 // Returns the size in bytes of the mapped memory. 156 uint32 size() const { 157 return size_; 158 } 159 // Returns the memory backing the file. 160 const void* GetChunkAt(uint32 offset) { 161 return &start_[offset]; 162 } 163 164 private: 165 HANDLE fmap_; 166 char* start_; 167 uint32 size_; 168}; 169 170// =========================================================================== 171// Validation of AudioManager::AUDIO_PCM_LINEAR 172// 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. 177 178// Test that can it be created and closed. 179TEST(WinAudioTest, PCMWaveStreamGetAndClose) { 180 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 181 if (!audio_man->HasAudioOutputDevices()) { 182 LOG(WARNING) << "No output device detected."; 183 return; 184 } 185 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(); 191} 192 193// Test that can it be cannot be created with invalid parameters. 194TEST(WinAudioTest, SanityOnMakeParams) { 195 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 196 if (!audio_man->HasAudioOutputDevices()) { 197 LOG(WARNING) << "No output device detected."; 198 return; 199 } 200 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))); 219} 220 221// Test that it can be opened and closed. 222TEST(WinAudioTest, PCMWaveStreamOpenAndClose) { 223 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 224 if (!audio_man->HasAudioOutputDevices()) { 225 LOG(WARNING) << "No output device detected."; 226 return; 227 } 228 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(); 235} 236 237// Test that it has a maximum packet size. 238TEST(WinAudioTest, PCMWaveStreamOpenLimit) { 239 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 240 if (!audio_man->HasAudioOutputDevices()) { 241 LOG(WARNING) << "No output device detected."; 242 return; 243 } 244 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(); 251} 252 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. 256TEST(WinAudioTest, PCMWaveSlowSource) { 257 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 258 if (!audio_man->HasAudioOutputDevices()) { 259 LOG(WARNING) << "No output device detected."; 260 return; 261 } 262 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(); 278} 279 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. 283TEST(WinAudioTest, PCMWaveStreamPlaySlowLoop) { 284 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 285 if (!audio_man->HasAudioOutputDevices()) { 286 LOG(WARNING) << "No output device detected."; 287 return; 288 } 289 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); 295 296 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); 297 298 EXPECT_TRUE(oas->Open()); 299 oas->SetVolume(1.0); 300 301 for (int ix = 0; ix != 5; ++ix) { 302 oas->Start(&source); 303 ::Sleep(10); 304 oas->Stop(); 305 } 306 oas->Close(); 307} 308 309 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. 313TEST(WinAudioTest, PCMWaveStreamPlay200HzTone44Kss) { 314 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 315 if (!audio_man->HasAudioOutputDevices()) { 316 LOG(WARNING) << "No output device detected."; 317 return; 318 } 319 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); 325 326 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); 327 328 EXPECT_TRUE(oas->Open()); 329 oas->SetVolume(1.0); 330 oas->Start(&source); 331 ::Sleep(500); 332 oas->Stop(); 333 oas->Close(); 334} 335 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. 340TEST(WinAudioTest, PCMWaveStreamPlay200HzTone22Kss) { 341 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 342 if (!audio_man->HasAudioOutputDevices()) { 343 LOG(WARNING) << "No output device detected."; 344 return; 345 } 346 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); 353 354 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate/2); 355 356 EXPECT_TRUE(oas->Open()); 357 358 oas->SetVolume(0.5); 359 oas->Start(&source); 360 ::Sleep(500); 361 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(); 369} 370 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. 374TEST(WinAudioTest, PushSourceFile16KHz) { 375 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 376 if (!audio_man->HasAudioOutputDevices()) { 377 LOG(WARNING) << "No output device detected."; 378 return; 379 } 380 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); 387 388 AudioOutputStream* oas = audio_man->MakeAudioOutputStream( 389 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, 390 kSampleRate, 16, kSamples100ms)); 391 ASSERT_TRUE(NULL != oas); 392 393 EXPECT_TRUE(oas->Open()); 394 395 oas->SetVolume(1.0); 396 oas->Start(&source); 397 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(); 404 } 405 406 // Play a little bit more of the file. 407 ::Sleep(500); 408 409 oas->Stop(); 410 oas->Close(); 411} 412 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. 416TEST(WinAudioTest, PCMWaveStreamPlayTwice200HzTone44Kss) { 417 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 418 if (!audio_man->HasAudioOutputDevices()) { 419 LOG(WARNING) << "No output device detected."; 420 return; 421 } 422 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); 428 429 SineWaveAudioSource source(1, 200.0, AudioParameters::kAudioCDSampleRate); 430 EXPECT_TRUE(oas->Open()); 431 oas->SetVolume(1.0); 432 433 // Play the wave for .5 seconds. 434 oas->Start(&source); 435 ::Sleep(500); 436 oas->Stop(); 437 438 // Sleep to give silence after stopping the AudioOutputStream. 439 ::Sleep(250); 440 441 // Start again and play for .5 seconds. 442 oas->Start(&source); 443 ::Sleep(500); 444 oas->Stop(); 445 446 oas->Close(); 447} 448 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. 452TEST(WinAudioTest, PCMWaveStreamPlay200HzToneLowLatency) { 453 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 454 if (!audio_man->HasAudioOutputDevices()) { 455 LOG(WARNING) << "No output device detected."; 456 return; 457 } 458 459 // The WASAPI API requires a correct COM environment. 460 ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA); 461 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); 474 475 SineWaveAudioSource source(1, 200, sample_rate); 476 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; 484 } 485 oas->SetVolume(1.0); 486 487 // Play the wave for .8 seconds. 488 oas->Start(&source); 489 ::Sleep(800); 490 oas->Stop(); 491 oas->Close(); 492} 493 494// Check that the pending bytes value is correct what the stream starts. 495TEST(WinAudioTest, PCMWaveStreamPendingBytes) { 496 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 497 if (!audio_man->HasAudioOutputDevices()) { 498 LOG(WARNING) << "No output device detected."; 499 return; 500 } 501 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); 507 508 NiceMock<MockAudioSource> source; 509 EXPECT_TRUE(oas->Open()); 510 511 uint32 bytes_100_ms = samples_100_ms * 2; 512 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; 520 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(); 545 } 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)); 555 556 oas->Start(&source); 557 ::Sleep(500); 558 oas->Stop(); 559 oas->Close(); 560} 561 562// Simple source that uses a SyncSocket to retrieve the audio data 563// from a potentially remote thread. 564class 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()); 573 } 574 ~SyncSocketSource() {} 575 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(); 584 } 585 virtual int OnMoreIOData(AudioBus* source, 586 AudioBus* dest, 587 AudioBuffersState buffers_state) { 588 NOTREACHED(); 589 return 0; 590 } 591 // AudioSourceCallback::OnError implementation: 592 virtual void OnError(AudioOutputStream* stream) { 593 } 594 595 private: 596 base::SyncSocket* socket_; 597 int data_size_; 598 scoped_ptr_malloc<float, base::ScopedPtrAlignedFree> data_; 599 scoped_ptr<AudioBus> audio_bus_; 600}; 601 602struct SyncThreadContext { 603 base::SyncSocket* socket; 604 int sample_rate; 605 int channels; 606 int frames; 607 double sine_freq; 608 uint32 packet_size_bytes; 609}; 610 611// This thread provides the data that the SyncSocketSource above needs 612// using the other end of a SyncSocket. The protocol is as follows: 613// 614// SyncSocketSource ---send 4 bytes ------------> SyncSocketThread 615// <--- audio packet ---------- 616// 617DWORD __stdcall SyncSocketThread(void* context) { 618 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context)); 619 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()); 625 626 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate); 627 const int kTwoSecFrames = ctx.sample_rate * 2; 628 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; 638 } 639 640 return 0; 641} 642 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. 651TEST(WinAudioTest, SyncSocketBasic) { 652 scoped_ptr<AudioManager> audio_man(AudioManager::Create()); 653 if (!audio_man->HasAudioOutputDevices()) { 654 LOG(WARNING) << "No output device detected."; 655 return; 656 } 657 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); 662 663 664 AudioOutputStream* oas = audio_man->MakeAudioOutputStream(params); 665 ASSERT_TRUE(NULL != oas); 666 667 ASSERT_TRUE(oas->Open()); 668 669 base::SyncSocket sockets[2]; 670 ASSERT_TRUE(base::SyncSocket::CreatePair(&sockets[0], &sockets[1])); 671 672 SyncSocketSource source(&sockets[0], params); 673 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]; 681 682 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread, 683 &thread_context, 0, NULL); 684 685 oas->Start(&source); 686 687 ::WaitForSingleObject(thread, INFINITE); 688 ::CloseHandle(thread); 689 690 oas->Stop(); 691 oas->Close(); 692} 693 694} // namespace media 695