OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <windows.h> | 5 #include <windows.h> |
6 #include <mmsystem.h> | 6 #include <mmsystem.h> |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <memory> | 10 #include <memory> |
11 | 11 |
12 #include "base/base_paths.h" | 12 #include "base/base_paths.h" |
13 #include "base/memory/aligned_memory.h" | 13 #include "base/memory/aligned_memory.h" |
14 #include "base/message_loop/message_loop.h" | 14 #include "base/message_loop/message_loop.h" |
15 #include "base/run_loop.h" | 15 #include "base/run_loop.h" |
16 #include "base/sync_socket.h" | 16 #include "base/sync_socket.h" |
| 17 #include "base/time/time.h" |
17 #include "base/win/scoped_com_initializer.h" | 18 #include "base/win/scoped_com_initializer.h" |
18 #include "base/win/windows_version.h" | 19 #include "base/win/windows_version.h" |
19 #include "media/audio/audio_io.h" | 20 #include "media/audio/audio_io.h" |
20 #include "media/audio/audio_manager.h" | 21 #include "media/audio/audio_manager.h" |
21 #include "media/audio/audio_unittest_util.h" | 22 #include "media/audio/audio_unittest_util.h" |
22 #include "media/audio/mock_audio_source_callback.h" | 23 #include "media/audio/mock_audio_source_callback.h" |
23 #include "media/audio/simple_sources.h" | 24 #include "media/audio/simple_sources.h" |
24 #include "media/base/limits.h" | 25 #include "media/base/limits.h" |
25 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
(...skipping 19 matching lines...) Expand all Loading... |
46 | 47 |
47 // This class allows to find out if the callbacks are occurring as | 48 // This class allows to find out if the callbacks are occurring as |
48 // expected and if any error has been reported. | 49 // expected and if any error has been reported. |
49 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { | 50 class TestSourceBasic : public AudioOutputStream::AudioSourceCallback { |
50 public: | 51 public: |
51 TestSourceBasic() | 52 TestSourceBasic() |
52 : callback_count_(0), | 53 : callback_count_(0), |
53 had_error_(0) { | 54 had_error_(0) { |
54 } | 55 } |
55 // AudioSourceCallback::OnMoreData implementation: | 56 // AudioSourceCallback::OnMoreData implementation: |
56 int OnMoreData(AudioBus* audio_bus, | 57 int OnMoreData(base::TimeDelta /* delay */, |
57 uint32_t total_bytes_delay, | 58 base::TimeTicks /* delay_timestamp */, |
58 uint32_t frames_skipped) override { | 59 int /* prior_frames_skipped */, |
| 60 AudioBus* dest) override { |
59 ++callback_count_; | 61 ++callback_count_; |
60 // Touch the channel memory value to make sure memory is good. | 62 // Touch the channel memory value to make sure memory is good. |
61 audio_bus->Zero(); | 63 dest->Zero(); |
62 return audio_bus->frames(); | 64 return dest->frames(); |
63 } | 65 } |
64 // AudioSourceCallback::OnError implementation: | 66 // AudioSourceCallback::OnError implementation: |
65 void OnError(AudioOutputStream* stream) override { ++had_error_; } | 67 void OnError(AudioOutputStream* stream) override { ++had_error_; } |
66 // Returns how many times OnMoreData() has been called. | 68 // Returns how many times OnMoreData() has been called. |
67 int callback_count() const { | 69 int callback_count() const { |
68 return callback_count_; | 70 return callback_count_; |
69 } | 71 } |
70 // Returns how many times the OnError callback was called. | 72 // Returns how many times the OnError callback was called. |
71 int had_error() const { | 73 int had_error() const { |
72 return had_error_; | 74 return had_error_; |
73 } | 75 } |
74 | 76 |
75 void set_error(bool error) { | 77 void set_error(bool error) { |
76 had_error_ += error ? 1 : 0; | 78 had_error_ += error ? 1 : 0; |
77 } | 79 } |
78 | 80 |
79 private: | 81 private: |
80 int callback_count_; | 82 int callback_count_; |
81 int had_error_; | 83 int had_error_; |
82 }; | 84 }; |
83 | 85 |
84 const int kMaxNumBuffers = 3; | 86 const int kMaxNumBuffers = 3; |
85 // Specializes TestSourceBasic to simulate a source that blocks for some time | 87 // Specializes TestSourceBasic to simulate a source that blocks for some time |
86 // in the OnMoreData callback. | 88 // in the OnMoreData callback. |
87 class TestSourceLaggy : public TestSourceBasic { | 89 class TestSourceLaggy : public TestSourceBasic { |
88 public: | 90 public: |
89 explicit TestSourceLaggy(int lag_in_ms) | 91 explicit TestSourceLaggy(int lag_in_ms) |
90 : lag_in_ms_(lag_in_ms) { | 92 : lag_in_ms_(lag_in_ms) { |
91 } | 93 } |
92 int OnMoreData(AudioBus* audio_bus, | 94 int OnMoreData(base::TimeDelta delay, |
93 uint32_t total_bytes_delay, | 95 base::TimeTicks delay_timestamp, |
94 uint32_t frames_skipped) override { | 96 int prior_frames_skipped, |
| 97 AudioBus* dest) override { |
95 // Call the base, which increments the callback_count_. | 98 // Call the base, which increments the callback_count_. |
96 TestSourceBasic::OnMoreData(audio_bus, total_bytes_delay, frames_skipped); | 99 TestSourceBasic::OnMoreData(delay, delay_timestamp, prior_frames_skipped, |
| 100 dest); |
97 if (callback_count() > kMaxNumBuffers) { | 101 if (callback_count() > kMaxNumBuffers) { |
98 ::Sleep(lag_in_ms_); | 102 ::Sleep(lag_in_ms_); |
99 } | 103 } |
100 return audio_bus->frames(); | 104 return dest->frames(); |
101 } | 105 } |
102 private: | 106 private: |
103 int lag_in_ms_; | 107 int lag_in_ms_; |
104 }; | 108 }; |
105 | 109 |
106 // Helper class to memory map an entire file. The mapping is read-only. Don't | 110 // Helper class to memory map an entire file. The mapping is read-only. Don't |
107 // use for gigabyte-sized files. Attempts to write to this memory generate | 111 // use for gigabyte-sized files. Attempts to write to this memory generate |
108 // memory access violations. | 112 // memory access violations. |
109 class ReadOnlyMappedFile { | 113 class ReadOnlyMappedFile { |
110 public: | 114 public: |
(...skipping 369 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
480 uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; | 484 uint32_t samples_100_ms = AudioParameters::kAudioCDSampleRate / 10; |
481 AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream( | 485 AudioOutputStream* oas = audio_manager_->MakeAudioOutputStream( |
482 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, | 486 AudioParameters(AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_MONO, |
483 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), | 487 AudioParameters::kAudioCDSampleRate, 16, samples_100_ms), |
484 std::string(), AudioManager::LogCallback()); | 488 std::string(), AudioManager::LogCallback()); |
485 ASSERT_TRUE(NULL != oas); | 489 ASSERT_TRUE(NULL != oas); |
486 | 490 |
487 NiceMock<MockAudioSourceCallback> source; | 491 NiceMock<MockAudioSourceCallback> source; |
488 EXPECT_TRUE(oas->Open()); | 492 EXPECT_TRUE(oas->Open()); |
489 | 493 |
490 uint32_t bytes_100_ms = samples_100_ms * 2; | 494 const base::TimeDelta 100_ms = base::TimeDelta::FromMilliseconds(100); |
| 495 const base::TimeDelta 200_ms = base::TimeDelta::FromMilliseconds(200); |
491 | 496 |
492 // Audio output stream has either a double or triple buffer scheme. | 497 // Audio output stream has either a double or triple buffer scheme. We expect |
493 // We expect the amount of pending bytes will reaching up to 2 times of | 498 // the delay to reach up to 200 ms depending on the number of buffers used. |
494 // |bytes_100_ms| depending on number of buffers used. | |
495 // From that it would decrease as we are playing the data but not providing | 499 // From that it would decrease as we are playing the data but not providing |
496 // new one. And then we will try to provide zero data so the amount of | 500 // new one. And then we will try to provide zero data so the amount of |
497 // pending bytes will go down and eventually read zero. | 501 // pending bytes will go down and eventually read zero. |
498 InSequence s; | 502 InSequence s; |
499 | 503 |
500 EXPECT_CALL(source, OnMoreData(NotNull(), 0, 0)).WillOnce(Invoke(ClearData)); | 504 EXPECT_CALL(source, OnMoreData(base::TimeDelta(), _, 0, NotNull())) |
| 505 .WillOnce(Invoke(ClearData)); |
501 | 506 |
502 // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this | 507 // Note: If AudioManagerWin::NumberOfWaveOutBuffers() ever changes, or if this |
503 // test is run on Vista, these expectations will fail. | 508 // test is run on Vista, these expectations will fail. |
504 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, 0)) | 509 EXPECT_CALL(source, OnMoreData(100_ms, _, 0, NotNull())) |
505 .WillOnce(Invoke(ClearData)); | 510 .WillOnce(Invoke(ClearData)); |
506 EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms, 0)) | 511 EXPECT_CALL(source, OnMoreData(200_ms, _, 0, NotNull())) |
507 .WillOnce(Invoke(ClearData)); | 512 .WillOnce(Invoke(ClearData)); |
508 EXPECT_CALL(source, OnMoreData(NotNull(), 2 * bytes_100_ms, 0)) | 513 EXPECT_CALL(source, OnMoreData(200_ms, _, 0, NotNull())) |
509 .Times(AnyNumber()) | 514 .Times(AnyNumber()) |
510 .WillRepeatedly(Return(0)); | 515 .WillRepeatedly(Return(0)); |
511 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_100_ms, 0)) | 516 EXPECT_CALL(source, OnMoreData(100_ms, _, 0, NotNull())) |
512 .Times(AnyNumber()) | 517 .Times(AnyNumber()) |
513 .WillRepeatedly(Return(0)); | 518 .WillRepeatedly(Return(0)); |
514 EXPECT_CALL(source, OnMoreData(NotNull(), 0, 0)) | 519 EXPECT_CALL(source, OnMoreData(base::TimeDelta(), _, 0, NotNull())) |
515 .Times(AnyNumber()) | 520 .Times(AnyNumber()) |
516 .WillRepeatedly(Return(0)); | 521 .WillRepeatedly(Return(0)); |
517 | 522 |
518 oas->Start(&source); | 523 oas->Start(&source); |
519 ::Sleep(500); | 524 ::Sleep(500); |
520 oas->Stop(); | 525 oas->Stop(); |
521 oas->Close(); | 526 oas->Close(); |
522 } | 527 } |
523 | 528 |
524 // Simple source that uses a SyncSocket to retrieve the audio data | 529 // Simple source that uses a SyncSocket to retrieve the audio data |
525 // from a potentially remote thread. | 530 // from a potentially remote thread. |
526 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback { | 531 class SyncSocketSource : public AudioOutputStream::AudioSourceCallback { |
527 public: | 532 public: |
528 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params) | 533 SyncSocketSource(base::SyncSocket* socket, const AudioParameters& params) |
529 : socket_(socket) { | 534 : socket_(socket), params_(params) { |
530 // Setup AudioBus wrapping data we'll receive over the sync socket. | 535 // Setup AudioBus wrapping data we'll receive over the sync socket. |
531 data_size_ = AudioBus::CalculateMemorySize(params); | 536 data_size_ = AudioBus::CalculateMemorySize(params); |
532 data_.reset(static_cast<float*>( | 537 data_.reset(static_cast<float*>( |
533 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment))); | 538 base::AlignedAlloc(data_size_, AudioBus::kChannelAlignment))); |
534 audio_bus_ = AudioBus::WrapMemory(params, data_.get()); | 539 audio_bus_ = AudioBus::WrapMemory(params, data_.get()); |
535 } | 540 } |
536 ~SyncSocketSource() override {} | 541 ~SyncSocketSource() override {} |
537 | 542 |
538 // AudioSourceCallback::OnMoreData implementation: | 543 // AudioSourceCallback::OnMoreData implementation: |
539 int OnMoreData(AudioBus* audio_bus, | 544 int OnMoreData(base::TimeDelta delay, |
540 uint32_t total_bytes_delay, | 545 base::TimeTicks /* delay_timestamp */, |
541 uint32_t frames_skipped) override { | 546 int /* prior_frames_skipped */, |
| 547 AudioBus* dest) override { |
| 548 uint32_t total_bytes_delay = |
| 549 delay.InSecondsF() * params_.GetBytesPerSecond(); |
542 socket_->Send(&total_bytes_delay, sizeof(total_bytes_delay)); | 550 socket_->Send(&total_bytes_delay, sizeof(total_bytes_delay)); |
543 uint32_t size = socket_->Receive(data_.get(), data_size_); | 551 uint32_t size = socket_->Receive(data_.get(), data_size_); |
544 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*audio_bus_->channel(0)), 0U); | 552 DCHECK_EQ(static_cast<size_t>(size) % sizeof(*dest_->channel(0)), 0U); |
545 audio_bus_->CopyTo(audio_bus); | 553 dest_->CopyTo(dest); |
546 return audio_bus_->frames(); | 554 return dest_->frames(); |
547 } | 555 } |
548 | 556 |
549 // AudioSourceCallback::OnError implementation: | 557 // AudioSourceCallback::OnError implementation: |
550 void OnError(AudioOutputStream* stream) override {} | 558 void OnError(AudioOutputStream* stream) override {} |
551 | 559 |
552 private: | 560 private: |
553 base::SyncSocket* socket_; | 561 base::SyncSocket* socket_; |
| 562 const AudioParameters params_; |
554 int data_size_; | 563 int data_size_; |
555 std::unique_ptr<float, base::AlignedFreeDeleter> data_; | 564 std::unique_ptr<float, base::AlignedFreeDeleter> data_; |
556 std::unique_ptr<AudioBus> audio_bus_; | 565 std::unique_ptr<AudioBus> audio_bus_; |
557 }; | 566 }; |
558 | 567 |
559 struct SyncThreadContext { | 568 struct SyncThreadContext { |
560 base::SyncSocket* socket; | 569 base::SyncSocket* socket; |
561 int sample_rate; | 570 int sample_rate; |
562 int channels; | 571 int channels; |
563 int frames; | 572 int frames; |
564 double sine_freq; | 573 double sine_freq; |
565 uint32_t packet_size_bytes; | 574 uint32_t packet_size_bytes; |
| 575 int bytes_per_second; |
566 }; | 576 }; |
567 | 577 |
568 // This thread provides the data that the SyncSocketSource above needs | 578 // This thread provides the data that the SyncSocketSource above needs |
569 // using the other end of a SyncSocket. The protocol is as follows: | 579 // using the other end of a SyncSocket. The protocol is as follows: |
570 // | 580 // |
571 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread | 581 // SyncSocketSource ---send 4 bytes ------------> SyncSocketThread |
572 // <--- audio packet ---------- | 582 // <--- audio packet ---------- |
573 // | 583 // |
574 DWORD __stdcall SyncSocketThread(void* context) { | 584 DWORD __stdcall SyncSocketThread(void* context) { |
575 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context)); | 585 SyncThreadContext& ctx = *(reinterpret_cast<SyncThreadContext*>(context)); |
576 | 586 |
577 // Setup AudioBus wrapping data we'll pass over the sync socket. | 587 // Setup AudioBus wrapping data we'll pass over the sync socket. |
578 std::unique_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>( | 588 std::unique_ptr<float, base::AlignedFreeDeleter> data(static_cast<float*>( |
579 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment))); | 589 base::AlignedAlloc(ctx.packet_size_bytes, AudioBus::kChannelAlignment))); |
580 std::unique_ptr<AudioBus> audio_bus = | 590 std::unique_ptr<AudioBus> audio_bus = |
581 AudioBus::WrapMemory(ctx.channels, ctx.frames, data.get()); | 591 AudioBus::WrapMemory(ctx.channels, ctx.frames, data.get()); |
582 | 592 |
583 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate); | 593 SineWaveAudioSource sine(1, ctx.sine_freq, ctx.sample_rate); |
584 const int kTwoSecFrames = ctx.sample_rate * 2; | 594 const int kTwoSecFrames = ctx.sample_rate * 2; |
585 | 595 |
586 uint32_t total_bytes_delay = 0; | 596 uint32_t total_bytes_delay = 0; |
587 int times = 0; | 597 int times = 0; |
588 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) { | 598 for (int ix = 0; ix < kTwoSecFrames; ix += ctx.frames) { |
589 if (ctx.socket->Receive(&total_bytes_delay, sizeof(total_bytes_delay)) == 0) | 599 if (ctx.socket->Receive(&total_bytes_delay, sizeof(total_bytes_delay)) == 0) |
590 break; | 600 break; |
591 if ((times > 0) && (total_bytes_delay < 1000)) __debugbreak(); | 601 if ((times > 0) && (total_bytes_delay < 1000)) __debugbreak(); |
592 sine.OnMoreData(audio_bus.get(), total_bytes_delay, 0); | 602 base::TimeDelta delay = base::TimeDelta::FromSecondsD( |
| 603 static_cast<double>(total_bytes_delay) / ctx.bytes_per_second); |
| 604 sine.OnMoreData(delay, base::TimeTicks::Now(), 0, audio_bus.get()); |
593 ctx.socket->Send(data.get(), ctx.packet_size_bytes); | 605 ctx.socket->Send(data.get(), ctx.packet_size_bytes); |
594 ++times; | 606 ++times; |
595 } | 607 } |
596 | 608 |
597 return 0; | 609 return 0; |
598 } | 610 } |
599 | 611 |
600 // Test the basic operation of AudioOutputStream used with a SyncSocket. | 612 // Test the basic operation of AudioOutputStream used with a SyncSocket. |
601 // The emphasis is to verify that it is possible to feed data to the audio | 613 // The emphasis is to verify that it is possible to feed data to the audio |
602 // layer using a source based on SyncSocket. In a real situation we would | 614 // layer using a source based on SyncSocket. In a real situation we would |
(...skipping 21 matching lines...) Expand all Loading... |
624 | 636 |
625 SyncSocketSource source(&sockets[0], params); | 637 SyncSocketSource source(&sockets[0], params); |
626 | 638 |
627 SyncThreadContext thread_context; | 639 SyncThreadContext thread_context; |
628 thread_context.sample_rate = params.sample_rate(); | 640 thread_context.sample_rate = params.sample_rate(); |
629 thread_context.sine_freq = 200.0; | 641 thread_context.sine_freq = 200.0; |
630 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params); | 642 thread_context.packet_size_bytes = AudioBus::CalculateMemorySize(params); |
631 thread_context.frames = params.frames_per_buffer(); | 643 thread_context.frames = params.frames_per_buffer(); |
632 thread_context.channels = params.channels(); | 644 thread_context.channels = params.channels(); |
633 thread_context.socket = &sockets[1]; | 645 thread_context.socket = &sockets[1]; |
| 646 thread_context.bytes_per_second = params.GetBytesPerSecond(); |
634 | 647 |
635 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread, | 648 HANDLE thread = ::CreateThread(NULL, 0, SyncSocketThread, |
636 &thread_context, 0, NULL); | 649 &thread_context, 0, NULL); |
637 | 650 |
638 oas->Start(&source); | 651 oas->Start(&source); |
639 | 652 |
640 ::WaitForSingleObject(thread, INFINITE); | 653 ::WaitForSingleObject(thread, INFINITE); |
641 ::CloseHandle(thread); | 654 ::CloseHandle(thread); |
642 | 655 |
643 oas->Stop(); | 656 oas->Stop(); |
644 oas->Close(); | 657 oas->Close(); |
645 } | 658 } |
646 | 659 |
647 } // namespace media | 660 } // namespace media |
OLD | NEW |