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/message_loop/message_loop.h"
10 #include "base/rand_util.h"
11 #include "base/synchronization/waitable_event.h"
12 #include "base/threading/thread.h"
13 #include "media/audio/audio_io.h"
14 #include "media/audio/simple_sources.h"
15 #include "media/audio/virtual_audio_input_stream.h"
16 #include "media/audio/virtual_audio_output_stream.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 using ::testing::AtLeast
;
22 using ::testing::InvokeWithoutArgs
;
23 using ::testing::NotNull
;
29 const AudioParameters
kParams(
30 AudioParameters::AUDIO_PCM_LOW_LATENCY
, CHANNEL_LAYOUT_STEREO
, 8000, 8, 10);
32 class MockInputCallback
: public AudioInputStream::AudioInputCallback
{
35 : data_pushed_(false, false) {
36 ON_CALL(*this, OnData(_
, _
, _
, _
, _
))
37 .WillByDefault(InvokeWithoutArgs(&data_pushed_
,
38 &base::WaitableEvent::Signal
));
41 virtual ~MockInputCallback() {}
43 MOCK_METHOD5(OnData
, void(AudioInputStream
* stream
, const uint8
* data
,
44 uint32 size
, uint32 hardware_delay_bytes
,
46 MOCK_METHOD1(OnClose
, void(AudioInputStream
* stream
));
47 MOCK_METHOD1(OnError
, void(AudioInputStream
* stream
));
49 void WaitForDataPushes() {
50 for (int i
= 0; i
< 3; ++i
) {
56 base::WaitableEvent data_pushed_
;
58 DISALLOW_COPY_AND_ASSIGN(MockInputCallback
);
61 class TestAudioSource
: public SineWaveAudioSource
{
64 : SineWaveAudioSource(
65 kParams
.channel_layout(), 200.0, kParams
.sample_rate()),
66 data_pulled_(false, false) {}
68 virtual ~TestAudioSource() {}
70 virtual int OnMoreData(AudioBus
* audio_bus
,
71 AudioBuffersState audio_buffers
) OVERRIDE
{
72 const int ret
= SineWaveAudioSource::OnMoreData(audio_bus
, audio_buffers
);
73 data_pulled_
.Signal();
77 virtual int OnMoreIOData(AudioBus
* source
,
79 AudioBuffersState audio_buffers
) OVERRIDE
{
81 SineWaveAudioSource::OnMoreIOData(source
, dest
, audio_buffers
);
82 data_pulled_
.Signal();
86 void WaitForDataPulls() {
87 for (int i
= 0; i
< 3; ++i
) {
93 base::WaitableEvent data_pulled_
;
95 DISALLOW_COPY_AND_ASSIGN(TestAudioSource
);
100 class VirtualAudioInputStreamTest
: public testing::TestWithParam
<bool> {
102 VirtualAudioInputStreamTest()
103 : audio_thread_(new base::Thread("AudioThread")),
104 worker_thread_(new base::Thread("AudioWorkerThread")),
106 closed_stream_(false, false) {
107 audio_thread_
->Start();
108 audio_message_loop_
= audio_thread_
->message_loop_proxy();
111 virtual ~VirtualAudioInputStreamTest() {
112 SyncWithAudioThread();
114 DCHECK(output_streams_
.empty());
115 DCHECK(stopped_output_streams_
.empty());
119 const bool worker_is_separate_thread
= GetParam();
120 stream_
= new VirtualAudioInputStream(
121 kParams
, GetWorkerLoop(worker_is_separate_thread
),
122 base::Bind(&base::DeletePointer
<VirtualAudioInputStream
>));
127 EXPECT_CALL(input_callback_
, OnClose(_
));
128 EXPECT_CALL(input_callback_
, OnData(_
, NotNull(), _
, _
, _
))
131 ASSERT_TRUE(!!stream_
);
132 stream_
->Start(&input_callback_
);
135 void CreateAndStartOneOutputStream() {
136 ASSERT_TRUE(!!stream_
);
137 AudioOutputStream
* const output_stream
= new VirtualAudioOutputStream(
140 base::Bind(&base::DeletePointer
<VirtualAudioOutputStream
>));
141 output_streams_
.push_back(output_stream
);
143 output_stream
->Open();
144 output_stream
->Start(&source_
);
148 ASSERT_TRUE(!!stream_
);
153 ASSERT_TRUE(!!stream_
);
156 closed_stream_
.Signal();
159 void WaitForDataToFlow() {
160 // Wait until audio thread is idle before calling output_streams_.size().
161 SyncWithAudioThread();
163 const int count
= output_streams_
.size();
164 for (int i
= 0; i
< count
; ++i
) {
165 source_
.WaitForDataPulls();
168 input_callback_
.WaitForDataPushes();
171 void WaitUntilClosed() {
172 closed_stream_
.Wait();
175 void StopAndCloseOneOutputStream() {
176 ASSERT_TRUE(!output_streams_
.empty());
177 AudioOutputStream
* const output_stream
= output_streams_
.front();
178 ASSERT_TRUE(!!output_stream
);
179 output_streams_
.pop_front();
181 output_stream
->Stop();
182 output_stream
->Close();
185 void StopFirstOutputStream() {
186 ASSERT_TRUE(!output_streams_
.empty());
187 AudioOutputStream
* const output_stream
= output_streams_
.front();
188 ASSERT_TRUE(!!output_stream
);
189 output_streams_
.pop_front();
190 output_stream
->Stop();
191 stopped_output_streams_
.push_back(output_stream
);
194 void StopSomeOutputStreams() {
195 ASSERT_LE(2, static_cast<int>(output_streams_
.size()));
196 for (int remaning
= base::RandInt(1, output_streams_
.size() - 1);
197 remaning
> 0; --remaning
) {
198 StopFirstOutputStream();
202 void RestartAllStoppedOutputStreams() {
203 typedef std::list
<AudioOutputStream
*>::const_iterator ConstIter
;
204 for (ConstIter it
= stopped_output_streams_
.begin();
205 it
!= stopped_output_streams_
.end(); ++it
) {
206 (*it
)->Start(&source_
);
207 output_streams_
.push_back(*it
);
209 stopped_output_streams_
.clear();
212 const scoped_refptr
<base::MessageLoopProxy
>& audio_message_loop() const {
213 return audio_message_loop_
;
216 const scoped_refptr
<base::MessageLoopProxy
>& GetWorkerLoop(
217 bool worker_is_separate_thread
) {
218 if (worker_is_separate_thread
) {
219 if (!worker_thread_
->IsRunning()) {
220 worker_thread_
->Start();
221 worker_message_loop_
= worker_thread_
->message_loop_proxy();
223 return worker_message_loop_
;
225 return audio_message_loop_
;
230 void SyncWithAudioThread() {
231 base::WaitableEvent
done(false, false);
232 audio_message_loop_
->PostTask(
234 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
238 scoped_ptr
<base::Thread
> audio_thread_
;
239 scoped_refptr
<base::MessageLoopProxy
> audio_message_loop_
;
240 scoped_ptr
<base::Thread
> worker_thread_
;
241 scoped_refptr
<base::MessageLoopProxy
> worker_message_loop_
;
243 VirtualAudioInputStream
* stream_
;
244 MockInputCallback input_callback_
;
245 base::WaitableEvent closed_stream_
;
247 std::list
<AudioOutputStream
*> output_streams_
;
248 std::list
<AudioOutputStream
*> stopped_output_streams_
;
249 TestAudioSource source_
;
251 DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest
);
254 #define RUN_ON_AUDIO_THREAD(method) \
255 audio_message_loop()->PostTask( \
256 FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method, \
257 base::Unretained(this)))
259 TEST_P(VirtualAudioInputStreamTest
, CreateAndClose
) {
260 RUN_ON_AUDIO_THREAD(Create
);
261 RUN_ON_AUDIO_THREAD(Close
);
265 TEST_P(VirtualAudioInputStreamTest
, NoOutputs
) {
266 RUN_ON_AUDIO_THREAD(Create
);
267 RUN_ON_AUDIO_THREAD(Start
);
269 RUN_ON_AUDIO_THREAD(Stop
);
270 RUN_ON_AUDIO_THREAD(Close
);
274 TEST_P(VirtualAudioInputStreamTest
, SingleOutput
) {
275 RUN_ON_AUDIO_THREAD(Create
);
276 RUN_ON_AUDIO_THREAD(Start
);
277 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
279 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
280 RUN_ON_AUDIO_THREAD(Stop
);
281 RUN_ON_AUDIO_THREAD(Close
);
285 TEST_P(VirtualAudioInputStreamTest
, SingleOutputPausedAndRestarted
) {
286 RUN_ON_AUDIO_THREAD(Create
);
287 RUN_ON_AUDIO_THREAD(Start
);
288 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
290 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
291 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
293 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
294 RUN_ON_AUDIO_THREAD(Stop
);
295 RUN_ON_AUDIO_THREAD(Close
);
299 TEST_P(VirtualAudioInputStreamTest
, MultipleOutputs
) {
300 RUN_ON_AUDIO_THREAD(Create
);
301 RUN_ON_AUDIO_THREAD(Start
);
302 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
304 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
305 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
307 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
308 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
310 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
311 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
313 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
314 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
315 RUN_ON_AUDIO_THREAD(Stop
);
316 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
317 RUN_ON_AUDIO_THREAD(Close
);
321 // A combination of all of the above tests with many output streams.
322 TEST_P(VirtualAudioInputStreamTest
, ComprehensiveTest
) {
323 static const int kNumOutputs
= 8;
324 static const int kHalfNumOutputs
= kNumOutputs
/ 2;
325 static const int kPauseIterations
= 5;
327 RUN_ON_AUDIO_THREAD(Create
);
328 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
329 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
331 RUN_ON_AUDIO_THREAD(Start
);
333 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
334 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
337 for (int i
= 0; i
< kPauseIterations
; ++i
) {
338 RUN_ON_AUDIO_THREAD(StopSomeOutputStreams
);
340 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
343 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
344 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
346 RUN_ON_AUDIO_THREAD(Stop
);
347 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
348 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
350 RUN_ON_AUDIO_THREAD(Close
);
354 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded
,
355 VirtualAudioInputStreamTest
,
356 ::testing::Values(false, true));