• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
FakeAudioConsumerTest()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 
~FakeAudioConsumerTest()30   virtual ~FakeAudioConsumerTest() {}
31 
ConsumeData(AudioBus * audio_bus)32   void ConsumeData(AudioBus* audio_bus) {
33     source_.OnMoreData(audio_bus, AudioBuffersState());
34   }
35 
RunOnAudioThread()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 
RunOnceOnAudioThread()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 
StopStartOnAudioThread()51   void StopStartOnAudioThread() {
52     ASSERT_TRUE(message_loop_.message_loop_proxy()->BelongsToCurrentThread());
53     fake_consumer_.Stop();
54     RunOnAudioThread();
55   }
56 
TimeCallbacksOnAudioThread(int callbacks)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 
EndTest(int callbacks)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.
TEST_F(FakeAudioConsumerTest,FakeStreamBasicCallback)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.
TEST_F(FakeAudioConsumerTest,TimeBetweenCallbacks)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
TEST_F(FakeAudioConsumerTest,StartStopClearsCallbacks)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