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