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(_
, _
, _
, _
)).WillByDefault(
36 InvokeWithoutArgs(&data_pushed_
, &base::WaitableEvent::Signal
));
39 virtual ~MockInputCallback() {}
42 void(AudioInputStream
* stream
,
43 const AudioBus
* source
,
44 uint32 hardware_delay_bytes
,
46 MOCK_METHOD1(OnError
, void(AudioInputStream
* stream
));
48 void WaitForDataPushes() {
49 for (int i
= 0; i
< 3; ++i
) {
55 base::WaitableEvent data_pushed_
;
57 DISALLOW_COPY_AND_ASSIGN(MockInputCallback
);
60 class TestAudioSource
: public SineWaveAudioSource
{
63 : SineWaveAudioSource(
64 kParams
.channel_layout(), 200.0, kParams
.sample_rate()),
65 data_pulled_(false, false) {}
67 ~TestAudioSource() override
{}
69 int OnMoreData(AudioBus
* audio_bus
, uint32 total_bytes_delay
) override
{
70 const int ret
= SineWaveAudioSource::OnMoreData(audio_bus
,
72 data_pulled_
.Signal();
76 void WaitForDataPulls() {
77 for (int i
= 0; i
< 3; ++i
) {
83 base::WaitableEvent data_pulled_
;
85 DISALLOW_COPY_AND_ASSIGN(TestAudioSource
);
90 class VirtualAudioInputStreamTest
: public testing::TestWithParam
<bool> {
92 VirtualAudioInputStreamTest()
93 : audio_thread_(new base::Thread("AudioThread")),
94 worker_thread_(new base::Thread("AudioWorkerThread")),
96 closed_stream_(false, false) {
97 audio_thread_
->Start();
98 audio_task_runner_
= audio_thread_
->task_runner();
101 virtual ~VirtualAudioInputStreamTest() {
102 SyncWithAudioThread();
104 DCHECK(output_streams_
.empty());
105 DCHECK(stopped_output_streams_
.empty());
109 const bool worker_is_separate_thread
= GetParam();
110 stream_
= new VirtualAudioInputStream(
111 kParams
, GetWorkerTaskRunner(worker_is_separate_thread
),
112 base::Bind(&base::DeletePointer
<VirtualAudioInputStream
>));
117 EXPECT_CALL(input_callback_
, OnData(_
, NotNull(), _
, _
)).Times(AtLeast(1));
119 ASSERT_TRUE(stream_
);
120 stream_
->Start(&input_callback_
);
123 void CreateAndStartOneOutputStream() {
124 ASSERT_TRUE(stream_
);
125 AudioOutputStream
* const output_stream
= new VirtualAudioOutputStream(
128 base::Bind(&base::DeletePointer
<VirtualAudioOutputStream
>));
129 output_streams_
.push_back(output_stream
);
131 output_stream
->Open();
132 output_stream
->Start(&source_
);
136 ASSERT_TRUE(stream_
);
141 ASSERT_TRUE(stream_
);
144 closed_stream_
.Signal();
147 void WaitForDataToFlow() {
148 // Wait until audio thread is idle before calling output_streams_.size().
149 SyncWithAudioThread();
151 const int count
= output_streams_
.size();
152 for (int i
= 0; i
< count
; ++i
) {
153 source_
.WaitForDataPulls();
156 input_callback_
.WaitForDataPushes();
159 void WaitUntilClosed() {
160 closed_stream_
.Wait();
163 void StopAndCloseOneOutputStream() {
164 ASSERT_TRUE(!output_streams_
.empty());
165 AudioOutputStream
* const output_stream
= output_streams_
.front();
166 ASSERT_TRUE(output_stream
);
167 output_streams_
.pop_front();
169 output_stream
->Stop();
170 output_stream
->Close();
173 void StopFirstOutputStream() {
174 ASSERT_TRUE(!output_streams_
.empty());
175 AudioOutputStream
* const output_stream
= output_streams_
.front();
176 ASSERT_TRUE(output_stream
);
177 output_streams_
.pop_front();
178 output_stream
->Stop();
179 stopped_output_streams_
.push_back(output_stream
);
182 void StopSomeOutputStreams() {
183 ASSERT_LE(2, static_cast<int>(output_streams_
.size()));
184 for (int remaning
= base::RandInt(1, output_streams_
.size() - 1);
185 remaning
> 0; --remaning
) {
186 StopFirstOutputStream();
190 void RestartAllStoppedOutputStreams() {
191 typedef std::list
<AudioOutputStream
*>::const_iterator ConstIter
;
192 for (ConstIter it
= stopped_output_streams_
.begin();
193 it
!= stopped_output_streams_
.end(); ++it
) {
194 (*it
)->Start(&source_
);
195 output_streams_
.push_back(*it
);
197 stopped_output_streams_
.clear();
200 const scoped_refptr
<base::SingleThreadTaskRunner
>& audio_task_runner() const {
201 return audio_task_runner_
;
204 const scoped_refptr
<base::SingleThreadTaskRunner
>& GetWorkerTaskRunner(
205 bool worker_is_separate_thread
) {
206 if (worker_is_separate_thread
) {
207 if (!worker_thread_
->IsRunning()) {
208 worker_thread_
->Start();
209 worker_task_runner_
= worker_thread_
->task_runner();
211 return worker_task_runner_
;
213 return audio_task_runner_
;
218 void SyncWithAudioThread() {
219 base::WaitableEvent
done(false, false);
220 audio_task_runner_
->PostTask(
222 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
226 scoped_ptr
<base::Thread
> audio_thread_
;
227 scoped_refptr
<base::SingleThreadTaskRunner
> audio_task_runner_
;
228 scoped_ptr
<base::Thread
> worker_thread_
;
229 scoped_refptr
<base::SingleThreadTaskRunner
> worker_task_runner_
;
231 VirtualAudioInputStream
* stream_
;
232 MockInputCallback input_callback_
;
233 base::WaitableEvent closed_stream_
;
235 std::list
<AudioOutputStream
*> output_streams_
;
236 std::list
<AudioOutputStream
*> stopped_output_streams_
;
237 TestAudioSource source_
;
239 DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest
);
242 #define RUN_ON_AUDIO_THREAD(method) \
243 audio_task_runner()->PostTask( \
244 FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method, \
245 base::Unretained(this)))
247 TEST_P(VirtualAudioInputStreamTest
, CreateAndClose
) {
248 RUN_ON_AUDIO_THREAD(Create
);
249 RUN_ON_AUDIO_THREAD(Close
);
253 TEST_P(VirtualAudioInputStreamTest
, NoOutputs
) {
254 RUN_ON_AUDIO_THREAD(Create
);
255 RUN_ON_AUDIO_THREAD(Start
);
257 RUN_ON_AUDIO_THREAD(Stop
);
258 RUN_ON_AUDIO_THREAD(Close
);
262 TEST_P(VirtualAudioInputStreamTest
, SingleOutput
) {
263 RUN_ON_AUDIO_THREAD(Create
);
264 RUN_ON_AUDIO_THREAD(Start
);
265 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
267 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
268 RUN_ON_AUDIO_THREAD(Stop
);
269 RUN_ON_AUDIO_THREAD(Close
);
273 TEST_P(VirtualAudioInputStreamTest
, SingleOutputPausedAndRestarted
) {
274 RUN_ON_AUDIO_THREAD(Create
);
275 RUN_ON_AUDIO_THREAD(Start
);
276 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
278 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
279 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
281 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
282 RUN_ON_AUDIO_THREAD(Stop
);
283 RUN_ON_AUDIO_THREAD(Close
);
287 TEST_P(VirtualAudioInputStreamTest
, MultipleOutputs
) {
288 RUN_ON_AUDIO_THREAD(Create
);
289 RUN_ON_AUDIO_THREAD(Start
);
290 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
292 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
293 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
295 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
296 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
298 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
299 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
301 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
302 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
303 RUN_ON_AUDIO_THREAD(Stop
);
304 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
305 RUN_ON_AUDIO_THREAD(Close
);
309 // A combination of all of the above tests with many output streams.
310 TEST_P(VirtualAudioInputStreamTest
, ComprehensiveTest
) {
311 static const int kNumOutputs
= 8;
312 static const int kHalfNumOutputs
= kNumOutputs
/ 2;
313 static const int kPauseIterations
= 5;
315 RUN_ON_AUDIO_THREAD(Create
);
316 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
317 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
319 RUN_ON_AUDIO_THREAD(Start
);
321 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
322 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
325 for (int i
= 0; i
< kPauseIterations
; ++i
) {
326 RUN_ON_AUDIO_THREAD(StopSomeOutputStreams
);
328 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
331 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
332 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
334 RUN_ON_AUDIO_THREAD(Stop
);
335 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
336 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
338 RUN_ON_AUDIO_THREAD(Close
);
342 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded
,
343 VirtualAudioInputStreamTest
,
344 ::testing::Values(false, true));