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.
8 #include "base/bind_helpers.h"
9 #include "base/rand_util.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/threading/thread.h"
12 #include "media/audio/audio_io.h"
13 #include "media/audio/simple_sources.h"
14 #include "media/audio/virtual_audio_input_stream.h"
15 #include "media/audio/virtual_audio_output_stream.h"
16 #include "testing/gmock/include/gmock/gmock.h"
17 #include "testing/gtest/include/gtest/gtest.h"
20 using ::testing::AtLeast;
21 using ::testing::InvokeWithoutArgs;
22 using ::testing::NotNull;
28 const AudioParameters kParams(
29 AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
31 class MockInputCallback : public AudioInputStream::AudioInputCallback {
34 : data_pushed_(false, false) {
35 ON_CALL(*this, OnData(_, _, _, _, _))
36 .WillByDefault(InvokeWithoutArgs(&data_pushed_,
37 &base::WaitableEvent::Signal));
40 virtual ~MockInputCallback() {}
42 MOCK_METHOD5(OnData, void(AudioInputStream* stream, const uint8* data,
43 uint32 size, uint32 hardware_delay_bytes,
45 MOCK_METHOD1(OnError, void(AudioInputStream* stream));
47 void WaitForDataPushes() {
48 for (int i = 0; i < 3; ++i) {
54 base::WaitableEvent data_pushed_;
56 DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
59 class TestAudioSource : public SineWaveAudioSource {
62 : SineWaveAudioSource(
63 kParams.channel_layout(), 200.0, kParams.sample_rate()),
64 data_pulled_(false, false) {}
66 virtual ~TestAudioSource() {}
68 virtual int OnMoreData(AudioBus* audio_bus,
69 AudioBuffersState audio_buffers) OVERRIDE {
70 const int ret = SineWaveAudioSource::OnMoreData(audio_bus, audio_buffers);
71 data_pulled_.Signal();
75 virtual int OnMoreIOData(AudioBus* source,
77 AudioBuffersState audio_buffers) OVERRIDE {
79 SineWaveAudioSource::OnMoreIOData(source, dest, audio_buffers);
80 data_pulled_.Signal();
84 void WaitForDataPulls() {
85 for (int i = 0; i < 3; ++i) {
91 base::WaitableEvent data_pulled_;
93 DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
98 class VirtualAudioInputStreamTest : public testing::TestWithParam<bool> {
100 VirtualAudioInputStreamTest()
101 : audio_thread_(new base::Thread("AudioThread")),
102 worker_thread_(new base::Thread("AudioWorkerThread")),
104 closed_stream_(false, false) {
105 audio_thread_->Start();
106 audio_task_runner_ = audio_thread_->message_loop_proxy();
109 virtual ~VirtualAudioInputStreamTest() {
110 SyncWithAudioThread();
112 DCHECK(output_streams_.empty());
113 DCHECK(stopped_output_streams_.empty());
117 const bool worker_is_separate_thread = GetParam();
118 stream_ = new VirtualAudioInputStream(
119 kParams, GetWorkerTaskRunner(worker_is_separate_thread),
120 base::Bind(&base::DeletePointer<VirtualAudioInputStream>));
125 EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _, _))
128 ASSERT_TRUE(!!stream_);
129 stream_->Start(&input_callback_);
132 void CreateAndStartOneOutputStream() {
133 ASSERT_TRUE(!!stream_);
134 AudioOutputStream* const output_stream = new VirtualAudioOutputStream(
137 base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
138 output_streams_.push_back(output_stream);
140 output_stream->Open();
141 output_stream->Start(&source_);
145 ASSERT_TRUE(!!stream_);
150 ASSERT_TRUE(!!stream_);
153 closed_stream_.Signal();
156 void WaitForDataToFlow() {
157 // Wait until audio thread is idle before calling output_streams_.size().
158 SyncWithAudioThread();
160 const int count = output_streams_.size();
161 for (int i = 0; i < count; ++i) {
162 source_.WaitForDataPulls();
165 input_callback_.WaitForDataPushes();
168 void WaitUntilClosed() {
169 closed_stream_.Wait();
172 void StopAndCloseOneOutputStream() {
173 ASSERT_TRUE(!output_streams_.empty());
174 AudioOutputStream* const output_stream = output_streams_.front();
175 ASSERT_TRUE(!!output_stream);
176 output_streams_.pop_front();
178 output_stream->Stop();
179 output_stream->Close();
182 void StopFirstOutputStream() {
183 ASSERT_TRUE(!output_streams_.empty());
184 AudioOutputStream* const output_stream = output_streams_.front();
185 ASSERT_TRUE(!!output_stream);
186 output_streams_.pop_front();
187 output_stream->Stop();
188 stopped_output_streams_.push_back(output_stream);
191 void StopSomeOutputStreams() {
192 ASSERT_LE(2, static_cast<int>(output_streams_.size()));
193 for (int remaning = base::RandInt(1, output_streams_.size() - 1);
194 remaning > 0; --remaning) {
195 StopFirstOutputStream();
199 void RestartAllStoppedOutputStreams() {
200 typedef std::list<AudioOutputStream*>::const_iterator ConstIter;
201 for (ConstIter it = stopped_output_streams_.begin();
202 it != stopped_output_streams_.end(); ++it) {
203 (*it)->Start(&source_);
204 output_streams_.push_back(*it);
206 stopped_output_streams_.clear();
209 const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
210 return audio_task_runner_;
213 const scoped_refptr<base::SingleThreadTaskRunner>& GetWorkerTaskRunner(
214 bool worker_is_separate_thread) {
215 if (worker_is_separate_thread) {
216 if (!worker_thread_->IsRunning()) {
217 worker_thread_->Start();
218 worker_task_runner_ = worker_thread_->message_loop_proxy();
220 return worker_task_runner_;
222 return audio_task_runner_;
227 void SyncWithAudioThread() {
228 base::WaitableEvent done(false, false);
229 audio_task_runner_->PostTask(
231 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
235 scoped_ptr<base::Thread> audio_thread_;
236 scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
237 scoped_ptr<base::Thread> worker_thread_;
238 scoped_refptr<base::SingleThreadTaskRunner> worker_task_runner_;
240 VirtualAudioInputStream* stream_;
241 MockInputCallback input_callback_;
242 base::WaitableEvent closed_stream_;
244 std::list<AudioOutputStream*> output_streams_;
245 std::list<AudioOutputStream*> stopped_output_streams_;
246 TestAudioSource source_;
248 DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
251 #define RUN_ON_AUDIO_THREAD(method) \
252 audio_task_runner()->PostTask( \
253 FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method, \
254 base::Unretained(this)))
256 TEST_P(VirtualAudioInputStreamTest, CreateAndClose) {
257 RUN_ON_AUDIO_THREAD(Create);
258 RUN_ON_AUDIO_THREAD(Close);
262 TEST_P(VirtualAudioInputStreamTest, NoOutputs) {
263 RUN_ON_AUDIO_THREAD(Create);
264 RUN_ON_AUDIO_THREAD(Start);
266 RUN_ON_AUDIO_THREAD(Stop);
267 RUN_ON_AUDIO_THREAD(Close);
271 TEST_P(VirtualAudioInputStreamTest, SingleOutput) {
272 RUN_ON_AUDIO_THREAD(Create);
273 RUN_ON_AUDIO_THREAD(Start);
274 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
276 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
277 RUN_ON_AUDIO_THREAD(Stop);
278 RUN_ON_AUDIO_THREAD(Close);
282 TEST_P(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
283 RUN_ON_AUDIO_THREAD(Create);
284 RUN_ON_AUDIO_THREAD(Start);
285 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
287 RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
288 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
290 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
291 RUN_ON_AUDIO_THREAD(Stop);
292 RUN_ON_AUDIO_THREAD(Close);
296 TEST_P(VirtualAudioInputStreamTest, MultipleOutputs) {
297 RUN_ON_AUDIO_THREAD(Create);
298 RUN_ON_AUDIO_THREAD(Start);
299 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
301 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
302 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
304 RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
305 RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
307 RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
308 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
310 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
311 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
312 RUN_ON_AUDIO_THREAD(Stop);
313 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
314 RUN_ON_AUDIO_THREAD(Close);
318 // A combination of all of the above tests with many output streams.
319 TEST_P(VirtualAudioInputStreamTest, ComprehensiveTest) {
320 static const int kNumOutputs = 8;
321 static const int kHalfNumOutputs = kNumOutputs / 2;
322 static const int kPauseIterations = 5;
324 RUN_ON_AUDIO_THREAD(Create);
325 for (int i = 0; i < kHalfNumOutputs; ++i) {
326 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
328 RUN_ON_AUDIO_THREAD(Start);
330 for (int i = 0; i < kHalfNumOutputs; ++i) {
331 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
334 for (int i = 0; i < kPauseIterations; ++i) {
335 RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
337 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
340 for (int i = 0; i < kHalfNumOutputs; ++i) {
341 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
343 RUN_ON_AUDIO_THREAD(Stop);
344 for (int i = 0; i < kHalfNumOutputs; ++i) {
345 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
347 RUN_ON_AUDIO_THREAD(Close);
351 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded,
352 VirtualAudioInputStreamTest,
353 ::testing::Values(false, true));