| 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 | 7 |
| 8 #include "base/basictypes.h" | 8 #include "base/basictypes.h" |
| 9 #include "base/environment.h" | 9 #include "base/environment.h" |
| 10 #include "base/file_util.h" | 10 #include "base/file_util.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 using base::win::ScopedCOMInitializer; | 37 using base::win::ScopedCOMInitializer; |
| 38 | 38 |
| 39 namespace media { | 39 namespace media { |
| 40 | 40 |
| 41 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw"; | 41 static const char kSpeechFile_16b_s_48k[] = "speech_16b_stereo_48kHz.raw"; |
| 42 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw"; | 42 static const char kSpeechFile_16b_s_44k[] = "speech_16b_stereo_44kHz.raw"; |
| 43 static const char kSpeechFile_16b_m_48k[] = "speech_16b_mono_48kHz.raw"; | 43 static const char kSpeechFile_16b_m_48k[] = "speech_16b_mono_48kHz.raw"; |
| 44 static const char kSpeechFile_16b_m_44k[] = "speech_16b_mono_44kHz.raw"; | 44 static const char kSpeechFile_16b_m_44k[] = "speech_16b_mono_44kHz.raw"; |
| 45 static const size_t kFileDurationMs = 20000; | 45 static const size_t kFileDurationMs = 20000; |
| 46 static const size_t kNumFileSegments = 2; | 46 static const size_t kNumFileSegments = 2; |
| 47 static const int kBitsPerSample = 16; |
| 47 | 48 |
| 48 static const size_t kMaxDeltaSamples = 1000; | 49 static const size_t kMaxDeltaSamples = 1000; |
| 49 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; | 50 static const char* kDeltaTimeMsFileName = "delta_times_ms.txt"; |
| 50 | 51 |
| 51 MATCHER_P(HasValidDelay, value, "") { | 52 MATCHER_P(HasValidDelay, value, "") { |
| 52 // It is difficult to come up with a perfect test condition for the delay | 53 // It is difficult to come up with a perfect test condition for the delay |
| 53 // estimation. For now, verify that the produced output delay is always | 54 // estimation. For now, verify that the produced output delay is always |
| 54 // larger than the selected buffer size. | 55 // larger than the selected buffer size. |
| 55 return arg.hardware_delay_bytes > value.hardware_delay_bytes; | 56 return arg.hardware_delay_bytes > value.hardware_delay_bytes; |
| 56 } | 57 } |
| 57 | 58 |
| 58 // Used to terminate a loop from a different thread than the loop belongs to. | 59 // Used to terminate a loop from a different thread than the loop belongs to. |
| 59 // |loop| should be a MessageLoopProxy. | 60 // |loop| should be a MessageLoopProxy. |
| 60 ACTION_P(QuitLoop, loop) { | 61 ACTION_P(QuitLoop, loop) { |
| 61 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 62 loop->PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
| 62 } | 63 } |
| 63 | 64 |
| 64 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { | 65 class MockAudioSourceCallback : public AudioOutputStream::AudioSourceCallback { |
| 65 public: | 66 public: |
| 66 MOCK_METHOD3(OnMoreData, uint32(uint8* dest, | 67 MOCK_METHOD2(OnMoreData, int(AudioBus* audio_bus, |
| 67 uint32 max_size, | 68 AudioBuffersState buffers_state)); |
| 68 AudioBuffersState buffers_state)); | |
| 69 MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code)); | 69 MOCK_METHOD2(OnError, void(AudioOutputStream* stream, int code)); |
| 70 }; | 70 }; |
| 71 | 71 |
| 72 // This audio source implementation should be used for manual tests only since | 72 // This audio source implementation should be used for manual tests only since |
| 73 // it takes about 20 seconds to play out a file. | 73 // it takes about 20 seconds to play out a file. |
| 74 class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback { | 74 class ReadFromFileAudioSource : public AudioOutputStream::AudioSourceCallback { |
| 75 public: | 75 public: |
| 76 explicit ReadFromFileAudioSource(const std::string& name) | 76 explicit ReadFromFileAudioSource(const std::string& name) |
| 77 : pos_(0), | 77 : pos_(0), |
| 78 previous_call_time_(base::Time::Now()), | 78 previous_call_time_(base::Time::Now()), |
| (...skipping 24 matching lines...) Expand all Loading... |
| 103 size_t elements_written = 0; | 103 size_t elements_written = 0; |
| 104 while (elements_written < elements_to_write_) { | 104 while (elements_written < elements_to_write_) { |
| 105 fprintf(text_file_, "%d\n", delta_times_[elements_written]); | 105 fprintf(text_file_, "%d\n", delta_times_[elements_written]); |
| 106 ++elements_written; | 106 ++elements_written; |
| 107 } | 107 } |
| 108 | 108 |
| 109 file_util::CloseFile(text_file_); | 109 file_util::CloseFile(text_file_); |
| 110 } | 110 } |
| 111 | 111 |
| 112 // AudioOutputStream::AudioSourceCallback implementation. | 112 // AudioOutputStream::AudioSourceCallback implementation. |
| 113 virtual uint32 OnMoreData(uint8* dest, | 113 virtual int OnMoreData(AudioBus* audio_bus, |
| 114 uint32 max_size, | 114 AudioBuffersState buffers_state) { |
| 115 AudioBuffersState buffers_state) { | |
| 116 // Store time difference between two successive callbacks in an array. | 115 // Store time difference between two successive callbacks in an array. |
| 117 // These values will be written to a file in the destructor. | 116 // These values will be written to a file in the destructor. |
| 118 int diff = (base::Time::Now() - previous_call_time_).InMilliseconds(); | 117 int diff = (base::Time::Now() - previous_call_time_).InMilliseconds(); |
| 119 previous_call_time_ = base::Time::Now(); | 118 previous_call_time_ = base::Time::Now(); |
| 120 if (elements_to_write_ < kMaxDeltaSamples) { | 119 if (elements_to_write_ < kMaxDeltaSamples) { |
| 121 delta_times_[elements_to_write_] = diff; | 120 delta_times_[elements_to_write_] = diff; |
| 122 ++elements_to_write_; | 121 ++elements_to_write_; |
| 123 } | 122 } |
| 124 | 123 |
| 124 int max_size = |
| 125 audio_bus->frames() * audio_bus->channels() * kBitsPerSample / 8; |
| 126 |
| 125 // Use samples read from a data file and fill up the audio buffer | 127 // Use samples read from a data file and fill up the audio buffer |
| 126 // provided to us in the callback. | 128 // provided to us in the callback. |
| 127 if (pos_ + static_cast<int>(max_size) > file_size()) | 129 if (pos_ + static_cast<int>(max_size) > file_size()) |
| 128 max_size = file_size() - pos_; | 130 max_size = file_size() - pos_; |
| 131 int frames = max_size / (audio_bus->channels() * kBitsPerSample / 8); |
| 129 if (max_size) { | 132 if (max_size) { |
| 130 memcpy(dest, file_->GetData() + pos_, max_size); | 133 audio_bus->FromInterleaved( |
| 134 file_->GetData() + pos_, frames, kBitsPerSample / 8); |
| 131 pos_ += max_size; | 135 pos_ += max_size; |
| 132 } | 136 } |
| 133 return max_size; | 137 return frames; |
| 134 } | 138 } |
| 135 | 139 |
| 136 virtual void OnError(AudioOutputStream* stream, int code) {} | 140 virtual void OnError(AudioOutputStream* stream, int code) {} |
| 137 | 141 |
| 138 int file_size() { return file_->GetDataSize(); } | 142 int file_size() { return file_->GetDataSize(); } |
| 139 | 143 |
| 140 private: | 144 private: |
| 141 scoped_refptr<DecoderBuffer> file_; | 145 scoped_refptr<DecoderBuffer> file_; |
| 142 scoped_array<int> delta_times_; | 146 scoped_array<int> delta_times_; |
| 143 int pos_; | 147 int pos_; |
| (...skipping 25 matching lines...) Expand all Loading... |
| 169 | 173 |
| 170 // Convenience method which creates a default AudioOutputStream object but | 174 // Convenience method which creates a default AudioOutputStream object but |
| 171 // also allows the user to modify the default settings. | 175 // also allows the user to modify the default settings. |
| 172 class AudioOutputStreamWrapper { | 176 class AudioOutputStreamWrapper { |
| 173 public: | 177 public: |
| 174 explicit AudioOutputStreamWrapper(AudioManager* audio_manager) | 178 explicit AudioOutputStreamWrapper(AudioManager* audio_manager) |
| 175 : com_init_(ScopedCOMInitializer::kMTA), | 179 : com_init_(ScopedCOMInitializer::kMTA), |
| 176 audio_man_(audio_manager), | 180 audio_man_(audio_manager), |
| 177 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), | 181 format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), |
| 178 channel_layout_(CHANNEL_LAYOUT_STEREO), | 182 channel_layout_(CHANNEL_LAYOUT_STEREO), |
| 179 bits_per_sample_(16) { | 183 bits_per_sample_(kBitsPerSample) { |
| 180 // Use native/mixing sample rate and 10ms frame size as default. | 184 // Use native/mixing sample rate and 10ms frame size as default. |
| 181 sample_rate_ = static_cast<int>( | 185 sample_rate_ = static_cast<int>( |
| 182 WASAPIAudioOutputStream::HardwareSampleRate(eConsole)); | 186 WASAPIAudioOutputStream::HardwareSampleRate(eConsole)); |
| 183 samples_per_packet_ = sample_rate_ / 100; | 187 samples_per_packet_ = sample_rate_ / 100; |
| 184 DCHECK(sample_rate_); | 188 DCHECK(sample_rate_); |
| 185 } | 189 } |
| 186 | 190 |
| 187 ~AudioOutputStreamWrapper() {} | 191 ~AudioOutputStreamWrapper() {} |
| 188 | 192 |
| 189 // Creates AudioOutputStream object using default parameters. | 193 // Creates AudioOutputStream object using default parameters. |
| (...skipping 264 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 454 EXPECT_TRUE(aos->Open()); | 458 EXPECT_TRUE(aos->Open()); |
| 455 | 459 |
| 456 // Derive the expected size in bytes of each packet. | 460 // Derive the expected size in bytes of each packet. |
| 457 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 461 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 458 (aosw.bits_per_sample() / 8); | 462 (aosw.bits_per_sample() / 8); |
| 459 | 463 |
| 460 // Set up expected minimum delay estimation. | 464 // Set up expected minimum delay estimation. |
| 461 AudioBuffersState state(0, bytes_per_packet); | 465 AudioBuffersState state(0, bytes_per_packet); |
| 462 | 466 |
| 463 // Wait for the first callback and verify its parameters. | 467 // Wait for the first callback and verify its parameters. |
| 464 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | 468 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 465 HasValidDelay(state))) | |
| 466 .WillOnce(DoAll( | 469 .WillOnce(DoAll( |
| 467 QuitLoop(loop.message_loop_proxy()), | 470 QuitLoop(loop.message_loop_proxy()), |
| 468 Return(bytes_per_packet))); | 471 Return(aosw.samples_per_packet()))); |
| 469 | 472 |
| 470 aos->Start(&source); | 473 aos->Start(&source); |
| 471 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 474 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 472 TestTimeouts::action_timeout()); | 475 TestTimeouts::action_timeout()); |
| 473 loop.Run(); | 476 loop.Run(); |
| 474 aos->Stop(); | 477 aos->Stop(); |
| 475 aos->Close(); | 478 aos->Close(); |
| 476 } | 479 } |
| 477 | 480 |
| 478 // Use a fixed packets size (independent of sample rate) and verify | 481 // Use a fixed packets size (independent of sample rate) and verify |
| (...skipping 14 matching lines...) Expand all Loading... |
| 493 EXPECT_TRUE(aos->Open()); | 496 EXPECT_TRUE(aos->Open()); |
| 494 | 497 |
| 495 // Derive the expected size in bytes of each packet. | 498 // Derive the expected size in bytes of each packet. |
| 496 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 499 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 497 (aosw.bits_per_sample() / 8); | 500 (aosw.bits_per_sample() / 8); |
| 498 | 501 |
| 499 // Set up expected minimum delay estimation. | 502 // Set up expected minimum delay estimation. |
| 500 AudioBuffersState state(0, bytes_per_packet); | 503 AudioBuffersState state(0, bytes_per_packet); |
| 501 | 504 |
| 502 // Ensure that callbacks start correctly. | 505 // Ensure that callbacks start correctly. |
| 503 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | 506 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 504 HasValidDelay(state))) | |
| 505 .WillOnce(DoAll( | 507 .WillOnce(DoAll( |
| 506 QuitLoop(loop.message_loop_proxy()), | 508 QuitLoop(loop.message_loop_proxy()), |
| 507 Return(bytes_per_packet))) | 509 Return(aosw.samples_per_packet()))) |
| 508 .WillRepeatedly(Return(bytes_per_packet)); | 510 .WillRepeatedly(Return(aosw.samples_per_packet())); |
| 509 | 511 |
| 510 aos->Start(&source); | 512 aos->Start(&source); |
| 511 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 513 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 512 TestTimeouts::action_timeout()); | 514 TestTimeouts::action_timeout()); |
| 513 loop.Run(); | 515 loop.Run(); |
| 514 aos->Stop(); | 516 aos->Stop(); |
| 515 aos->Close(); | 517 aos->Close(); |
| 516 } | 518 } |
| 517 | 519 |
| 518 TEST(WASAPIAudioOutputStreamTest, Mono) { | 520 TEST(WASAPIAudioOutputStreamTest, Mono) { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 529 AudioOutputStream* aos = aosw.Create(CHANNEL_LAYOUT_MONO); | 531 AudioOutputStream* aos = aosw.Create(CHANNEL_LAYOUT_MONO); |
| 530 EXPECT_TRUE(aos->Open()); | 532 EXPECT_TRUE(aos->Open()); |
| 531 | 533 |
| 532 // Derive the expected size in bytes of each packet. | 534 // Derive the expected size in bytes of each packet. |
| 533 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 535 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 534 (aosw.bits_per_sample() / 8); | 536 (aosw.bits_per_sample() / 8); |
| 535 | 537 |
| 536 // Set up expected minimum delay estimation. | 538 // Set up expected minimum delay estimation. |
| 537 AudioBuffersState state(0, bytes_per_packet); | 539 AudioBuffersState state(0, bytes_per_packet); |
| 538 | 540 |
| 539 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | 541 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 540 HasValidDelay(state))) | |
| 541 .WillOnce(DoAll( | 542 .WillOnce(DoAll( |
| 542 QuitLoop(loop.message_loop_proxy()), | 543 QuitLoop(loop.message_loop_proxy()), |
| 543 Return(bytes_per_packet))) | 544 Return(aosw.samples_per_packet()))) |
| 544 .WillRepeatedly(Return(bytes_per_packet)); | 545 .WillRepeatedly(Return(aosw.samples_per_packet())); |
| 545 | 546 |
| 546 aos->Start(&source); | 547 aos->Start(&source); |
| 547 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 548 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 548 TestTimeouts::action_timeout()); | 549 TestTimeouts::action_timeout()); |
| 549 loop.Run(); | 550 loop.Run(); |
| 550 aos->Stop(); | 551 aos->Stop(); |
| 551 aos->Close(); | 552 aos->Close(); |
| 552 } | 553 } |
| 553 | 554 |
| 554 // This test is intended for manual tests and should only be enabled | 555 // This test is intended for manual tests and should only be enabled |
| (...skipping 227 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 782 EXPECT_TRUE(aos->Open()); | 783 EXPECT_TRUE(aos->Open()); |
| 783 | 784 |
| 784 // Derive the expected size in bytes of each packet. | 785 // Derive the expected size in bytes of each packet. |
| 785 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 786 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 786 (aosw.bits_per_sample() / 8); | 787 (aosw.bits_per_sample() / 8); |
| 787 | 788 |
| 788 // Set up expected minimum delay estimation. | 789 // Set up expected minimum delay estimation. |
| 789 AudioBuffersState state(0, bytes_per_packet); | 790 AudioBuffersState state(0, bytes_per_packet); |
| 790 | 791 |
| 791 // Wait for the first callback and verify its parameters. | 792 // Wait for the first callback and verify its parameters. |
| 792 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | 793 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 793 HasValidDelay(state))) | |
| 794 .WillOnce(DoAll( | 794 .WillOnce(DoAll( |
| 795 QuitLoop(loop.message_loop_proxy()), | 795 QuitLoop(loop.message_loop_proxy()), |
| 796 Return(bytes_per_packet))) | 796 Return(aosw.samples_per_packet()))) |
| 797 .WillRepeatedly(Return(bytes_per_packet)); | 797 .WillRepeatedly(Return(aosw.samples_per_packet())); |
| 798 | 798 |
| 799 aos->Start(&source); | 799 aos->Start(&source); |
| 800 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 800 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 801 TestTimeouts::action_timeout()); | 801 TestTimeouts::action_timeout()); |
| 802 loop.Run(); | 802 loop.Run(); |
| 803 aos->Stop(); | 803 aos->Stop(); |
| 804 aos->Close(); | 804 aos->Close(); |
| 805 } | 805 } |
| 806 | 806 |
| 807 // Verify that we can open and start the output stream in exclusive mode at | 807 // Verify that we can open and start the output stream in exclusive mode at |
| (...skipping 16 matching lines...) Expand all Loading... |
| 824 EXPECT_TRUE(aos->Open()); | 824 EXPECT_TRUE(aos->Open()); |
| 825 | 825 |
| 826 // Derive the expected size in bytes of each packet. | 826 // Derive the expected size in bytes of each packet. |
| 827 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * | 827 uint32 bytes_per_packet = aosw.channels() * aosw.samples_per_packet() * |
| 828 (aosw.bits_per_sample() / 8); | 828 (aosw.bits_per_sample() / 8); |
| 829 | 829 |
| 830 // Set up expected minimum delay estimation. | 830 // Set up expected minimum delay estimation. |
| 831 AudioBuffersState state(0, bytes_per_packet); | 831 AudioBuffersState state(0, bytes_per_packet); |
| 832 | 832 |
| 833 // Wait for the first callback and verify its parameters. | 833 // Wait for the first callback and verify its parameters. |
| 834 EXPECT_CALL(source, OnMoreData(NotNull(), bytes_per_packet, | 834 EXPECT_CALL(source, OnMoreData(NotNull(), HasValidDelay(state))) |
| 835 HasValidDelay(state))) | |
| 836 .WillOnce(DoAll( | 835 .WillOnce(DoAll( |
| 837 QuitLoop(loop.message_loop_proxy()), | 836 QuitLoop(loop.message_loop_proxy()), |
| 838 Return(bytes_per_packet))) | 837 Return(aosw.samples_per_packet()))) |
| 839 .WillRepeatedly(Return(bytes_per_packet)); | 838 .WillRepeatedly(Return(aosw.samples_per_packet())); |
| 840 | 839 |
| 841 aos->Start(&source); | 840 aos->Start(&source); |
| 842 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), | 841 loop.PostDelayedTask(FROM_HERE, MessageLoop::QuitClosure(), |
| 843 TestTimeouts::action_timeout()); | 842 TestTimeouts::action_timeout()); |
| 844 loop.Run(); | 843 loop.Run(); |
| 845 aos->Stop(); | 844 aos->Stop(); |
| 846 aos->Close(); | 845 aos->Close(); |
| 847 } | 846 } |
| 848 | 847 |
| 849 } // namespace media | 848 } // namespace media |
| OLD | NEW |