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