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.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::Test
{
102 VirtualAudioInputStreamTest()
103 : audio_thread_(new base::Thread("AudioThread")),
105 closed_stream_(false, false) {
106 audio_thread_
->Start();
107 audio_message_loop_
= audio_thread_
->message_loop_proxy();
110 virtual ~VirtualAudioInputStreamTest() {
111 SyncWithAudioThread();
113 DCHECK(output_streams_
.empty());
114 DCHECK(stopped_output_streams_
.empty());
118 stream_
= new VirtualAudioInputStream(
119 kParams
, audio_message_loop_
,
120 base::Bind(&base::DeletePointer
<VirtualAudioInputStream
>));
125 EXPECT_CALL(input_callback_
, OnClose(_
));
126 EXPECT_CALL(input_callback_
, OnData(_
, NotNull(), _
, _
, _
))
129 ASSERT_TRUE(!!stream_
);
130 stream_
->Start(&input_callback_
);
133 void CreateAndStartOneOutputStream() {
134 ASSERT_TRUE(!!stream_
);
135 AudioOutputStream
* const output_stream
=
136 new VirtualAudioOutputStream(
137 kParams
, audio_message_loop_
, stream_
,
138 base::Bind(&base::DeletePointer
<VirtualAudioOutputStream
>));
139 output_streams_
.push_back(output_stream
);
141 output_stream
->Open();
142 output_stream
->Start(&source_
);
146 ASSERT_TRUE(!!stream_
);
151 ASSERT_TRUE(!!stream_
);
154 closed_stream_
.Signal();
157 void WaitForDataToFlow() {
158 // Wait until audio thread is idle before calling output_streams_.size().
159 SyncWithAudioThread();
161 const int count
= output_streams_
.size();
162 for (int i
= 0; i
< count
; ++i
) {
163 source_
.WaitForDataPulls();
166 input_callback_
.WaitForDataPushes();
169 void WaitUntilClosed() {
170 closed_stream_
.Wait();
173 void StopAndCloseOneOutputStream() {
174 ASSERT_TRUE(!output_streams_
.empty());
175 AudioOutputStream
* const output_stream
= output_streams_
.front();
176 ASSERT_TRUE(!!output_stream
);
177 output_streams_
.pop_front();
179 output_stream
->Stop();
180 output_stream
->Close();
183 void StopFirstOutputStream() {
184 ASSERT_TRUE(!output_streams_
.empty());
185 AudioOutputStream
* const output_stream
= output_streams_
.front();
186 ASSERT_TRUE(!!output_stream
);
187 output_streams_
.pop_front();
188 output_stream
->Stop();
189 stopped_output_streams_
.push_back(output_stream
);
192 void StopSomeOutputStreams() {
193 ASSERT_LE(2, static_cast<int>(output_streams_
.size()));
194 for (int remaning
= base::RandInt(1, output_streams_
.size() - 1);
195 remaning
> 0; --remaning
) {
196 StopFirstOutputStream();
200 void RestartAllStoppedOutputStreams() {
201 typedef std::list
<AudioOutputStream
*>::const_iterator ConstIter
;
202 for (ConstIter it
= stopped_output_streams_
.begin();
203 it
!= stopped_output_streams_
.end(); ++it
) {
204 (*it
)->Start(&source_
);
205 output_streams_
.push_back(*it
);
207 stopped_output_streams_
.clear();
210 const scoped_refptr
<base::MessageLoopProxy
>& audio_message_loop() const {
211 return audio_message_loop_
;
215 void SyncWithAudioThread() {
216 base::WaitableEvent
done(false, false);
217 audio_message_loop_
->PostTask(
219 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&done
)));
223 scoped_ptr
<base::Thread
> audio_thread_
;
224 scoped_refptr
<base::MessageLoopProxy
> audio_message_loop_
;
226 VirtualAudioInputStream
* stream_
;
227 MockInputCallback input_callback_
;
228 base::WaitableEvent closed_stream_
;
230 std::list
<AudioOutputStream
*> output_streams_
;
231 std::list
<AudioOutputStream
*> stopped_output_streams_
;
232 TestAudioSource source_
;
234 DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest
);
237 #define RUN_ON_AUDIO_THREAD(method) \
238 audio_message_loop()->PostTask( \
239 FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method, \
240 base::Unretained(this)))
242 TEST_F(VirtualAudioInputStreamTest
, CreateAndClose
) {
243 RUN_ON_AUDIO_THREAD(Create
);
244 RUN_ON_AUDIO_THREAD(Close
);
248 TEST_F(VirtualAudioInputStreamTest
, NoOutputs
) {
249 RUN_ON_AUDIO_THREAD(Create
);
250 RUN_ON_AUDIO_THREAD(Start
);
252 RUN_ON_AUDIO_THREAD(Stop
);
253 RUN_ON_AUDIO_THREAD(Close
);
257 TEST_F(VirtualAudioInputStreamTest
, SingleOutput
) {
258 RUN_ON_AUDIO_THREAD(Create
);
259 RUN_ON_AUDIO_THREAD(Start
);
260 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
262 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
263 RUN_ON_AUDIO_THREAD(Stop
);
264 RUN_ON_AUDIO_THREAD(Close
);
268 TEST_F(VirtualAudioInputStreamTest
, SingleOutputPausedAndRestarted
) {
269 RUN_ON_AUDIO_THREAD(Create
);
270 RUN_ON_AUDIO_THREAD(Start
);
271 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
273 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
274 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
276 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
277 RUN_ON_AUDIO_THREAD(Stop
);
278 RUN_ON_AUDIO_THREAD(Close
);
282 TEST_F(VirtualAudioInputStreamTest
, MultipleOutputs
) {
283 RUN_ON_AUDIO_THREAD(Create
);
284 RUN_ON_AUDIO_THREAD(Start
);
285 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
287 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
288 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
290 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
291 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
293 RUN_ON_AUDIO_THREAD(StopFirstOutputStream
);
294 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
296 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
297 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
298 RUN_ON_AUDIO_THREAD(Stop
);
299 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
300 RUN_ON_AUDIO_THREAD(Close
);
304 // A combination of all of the above tests with many output streams.
305 TEST_F(VirtualAudioInputStreamTest
, ComprehensiveTest
) {
306 static const int kNumOutputs
= 8;
307 static const int kHalfNumOutputs
= kNumOutputs
/ 2;
308 static const int kPauseIterations
= 5;
310 RUN_ON_AUDIO_THREAD(Create
);
311 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
312 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
314 RUN_ON_AUDIO_THREAD(Start
);
316 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
317 RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream
);
320 for (int i
= 0; i
< kPauseIterations
; ++i
) {
321 RUN_ON_AUDIO_THREAD(StopSomeOutputStreams
);
323 RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams
);
326 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
327 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
329 RUN_ON_AUDIO_THREAD(Stop
);
330 for (int i
= 0; i
< kHalfNumOutputs
; ++i
) {
331 RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream
);
333 RUN_ON_AUDIO_THREAD(Close
);