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