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 "base/bind.h" 6 #include "base/message_loop/message_loop.h" 7 #include "base/time/time.h" 8 #include "media/audio/audio_buffers_state.h" 9 #include "media/audio/audio_parameters.h" 10 #include "media/audio/fake_audio_consumer.h" 11 #include "media/audio/simple_sources.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 namespace media { 15 16 static const int kTestCallbacks = 5; 17 18 class FakeAudioConsumerTest : public testing::Test { 19 public: 20 FakeAudioConsumerTest() 21 : params_( 22 AudioParameters::AUDIO_FAKE, CHANNEL_LAYOUT_STEREO, 44100, 8, 128), 23 fake_consumer_(message_loop_.message_loop_proxy(), params_), 24 source_(params_.channels(), 200.0, params_.sample_rate()) { 25 time_between_callbacks_ = base::TimeDelta::FromMicroseconds( 26 params_.frames_per_buffer() * base::Time::kMicrosecondsPerSecond / 27 static_cast<float>(params_.sample_rate())); 28 } 29 30 virtual ~FakeAudioConsumerTest() {} 31 32 void ConsumeData(AudioBus* audio_bus) { 33 source_.OnMoreData(audio_bus, AudioBuffersState()); 34 } 35 36 void RunOnAudioThread() { 37 ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); 38 fake_consumer_.Start(base::Bind( 39 &FakeAudioConsumerTest::ConsumeData, base::Unretained(this))); 40 } 41 42 void RunOnceOnAudioThread() { 43 ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); 44 RunOnAudioThread(); 45 // Start() should immediately post a task to run the source callback, so we 46 // should end up with only a single callback being run. 47 message_loop_.PostTask(FROM_HERE, base::Bind( 48 &FakeAudioConsumerTest::EndTest, base::Unretained(this), 1)); 49 } 50 51 void StopStartOnAudioThread() { 52 ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); 53 fake_consumer_.Stop(); 54 RunOnAudioThread(); 55 } 56 57 void TimeCallbacksOnAudioThread(int callbacks) { 58 ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); 59 60 if (source_.callbacks() == 0) { 61 RunOnAudioThread(); 62 start_time_ = base::TimeTicks::Now(); 63 } 64 65 // Keep going until we've seen the requested number of callbacks. 66 if (source_.callbacks() < callbacks) { 67 message_loop_.PostDelayedTask(FROM_HERE, base::Bind( 68 &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, 69 base::Unretained(this), callbacks), time_between_callbacks_ / 2); 70 } else { 71 end_time_ = base::TimeTicks::Now(); 72 EndTest(callbacks); 73 } 74 } 75 76 void EndTest(int callbacks) { 77 ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread()); 78 fake_consumer_.Stop(); 79 EXPECT_LE(callbacks, source_.callbacks()); 80 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); 81 } 82 83 protected: 84 base::MessageLoop message_loop_; 85 AudioParameters params_; 86 FakeAudioConsumer fake_consumer_; 87 SineWaveAudioSource source_; 88 base::TimeTicks start_time_; 89 base::TimeTicks end_time_; 90 base::TimeDelta time_between_callbacks_; 91 92 private: 93 DISALLOW_COPY_AND_ASSIGN(FakeAudioConsumerTest); 94 }; 95 96 // Ensure the fake audio stream runs on the audio thread and handles fires 97 // callbacks to the AudioSourceCallback. 98 TEST_F(FakeAudioConsumerTest, FakeStreamBasicCallback) { 99 message_loop_.PostTask(FROM_HERE, base::Bind( 100 &FakeAudioConsumerTest::RunOnceOnAudioThread, 101 base::Unretained(this))); 102 message_loop_.Run(); 103 } 104 105 // Ensure the time between callbacks is sane. 106 TEST_F(FakeAudioConsumerTest, TimeBetweenCallbacks) { 107 message_loop_.PostTask(FROM_HERE, base::Bind( 108 &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, 109 base::Unretained(this), kTestCallbacks)); 110 message_loop_.Run(); 111 112 // There are only (kTestCallbacks - 1) intervals between kTestCallbacks. 113 base::TimeDelta actual_time_between_callbacks = 114 (end_time_ - start_time_) / (source_.callbacks() - 1); 115 116 // Ensure callback time is no faster than the expected time between callbacks. 117 EXPECT_TRUE(actual_time_between_callbacks >= time_between_callbacks_); 118 119 // Softly check if the callback time is no slower than twice the expected time 120 // between callbacks. Since this test runs on the bots we can't be too strict 121 // with the bounds. 122 if (actual_time_between_callbacks > 2 * time_between_callbacks_) 123 LOG(ERROR) << "Time between fake audio callbacks is too large!"; 124 } 125 126 // Ensure Start()/Stop() on the stream doesn't generate too many callbacks. See 127 // http://crbug.com/159049 128 TEST_F(FakeAudioConsumerTest, StartStopClearsCallbacks) { 129 message_loop_.PostTask(FROM_HERE, base::Bind( 130 &FakeAudioConsumerTest::TimeCallbacksOnAudioThread, 131 base::Unretained(this), kTestCallbacks)); 132 133 // Issue a Stop() / Start() in between expected callbacks to maximize the 134 // chance of catching the FakeAudioOutputStream doing the wrong thing. 135 message_loop_.PostDelayedTask(FROM_HERE, base::Bind( 136 &FakeAudioConsumerTest::StopStartOnAudioThread, 137 base::Unretained(this)), time_between_callbacks_ / 2); 138 139 // EndTest() will ensure the proper number of callbacks have occurred. 140 message_loop_.Run(); 141 } 142 143 } // namespace media 144