fake_audio_consumer_unittest.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
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.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
14namespace media {
15
16static const int kTestCallbacks = 5;
17
18class 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.
98TEST_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.
106TEST_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
128TEST_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