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