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));