Upstream version 5.34.92.0
[platform/framework/web/crosswalk.git] / src / media / audio / virtual_audio_input_stream_unittest.cc
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.
4
5 #include <list>
6
7 #include "base/bind.h"
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"
18
19 using ::testing::_;
20 using ::testing::AtLeast;
21 using ::testing::InvokeWithoutArgs;
22 using ::testing::NotNull;
23
24 namespace media {
25
26 namespace {
27
28 const AudioParameters kParams(
29     AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
30
31 class MockInputCallback : public AudioInputStream::AudioInputCallback {
32  public:
33   MockInputCallback()
34       : data_pushed_(false, false) {
35     ON_CALL(*this, OnData(_, _, _, _, _))
36         .WillByDefault(InvokeWithoutArgs(&data_pushed_,
37                                          &base::WaitableEvent::Signal));
38   }
39
40   virtual ~MockInputCallback() {}
41
42   MOCK_METHOD5(OnData, void(AudioInputStream* stream, const uint8* data,
43                             uint32 size, uint32 hardware_delay_bytes,
44                             double volume));
45   MOCK_METHOD1(OnError, void(AudioInputStream* stream));
46
47   void WaitForDataPushes() {
48     for (int i = 0; i < 3; ++i) {
49       data_pushed_.Wait();
50     }
51   }
52
53  private:
54   base::WaitableEvent data_pushed_;
55
56   DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
57 };
58
59 class TestAudioSource : public SineWaveAudioSource {
60  public:
61   TestAudioSource()
62       : SineWaveAudioSource(
63             kParams.channel_layout(), 200.0, kParams.sample_rate()),
64         data_pulled_(false, false) {}
65
66   virtual ~TestAudioSource() {}
67
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();
72     return ret;
73   }
74
75   virtual int OnMoreIOData(AudioBus* source,
76                            AudioBus* dest,
77                            AudioBuffersState audio_buffers) OVERRIDE {
78     const int ret =
79         SineWaveAudioSource::OnMoreIOData(source, dest, audio_buffers);
80     data_pulled_.Signal();
81     return ret;
82   }
83
84   void WaitForDataPulls() {
85     for (int i = 0; i < 3; ++i) {
86       data_pulled_.Wait();
87     }
88   }
89
90  private:
91   base::WaitableEvent data_pulled_;
92
93   DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
94 };
95
96 }  // namespace
97
98 class VirtualAudioInputStreamTest : public testing::TestWithParam<bool> {
99  public:
100   VirtualAudioInputStreamTest()
101       : audio_thread_(new base::Thread("AudioThread")),
102         worker_thread_(new base::Thread("AudioWorkerThread")),
103         stream_(NULL),
104         closed_stream_(false, false) {
105     audio_thread_->Start();
106     audio_task_runner_ = audio_thread_->message_loop_proxy();
107   }
108
109   virtual ~VirtualAudioInputStreamTest() {
110     SyncWithAudioThread();
111
112     DCHECK(output_streams_.empty());
113     DCHECK(stopped_output_streams_.empty());
114   }
115
116   void Create() {
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>));
121     stream_->Open();
122   }
123
124   void Start() {
125     EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _, _))
126         .Times(AtLeast(1));
127
128     ASSERT_TRUE(!!stream_);
129     stream_->Start(&input_callback_);
130   }
131
132   void CreateAndStartOneOutputStream() {
133     ASSERT_TRUE(!!stream_);
134     AudioOutputStream* const output_stream = new VirtualAudioOutputStream(
135         kParams,
136         stream_,
137         base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
138     output_streams_.push_back(output_stream);
139
140     output_stream->Open();
141     output_stream->Start(&source_);
142   }
143
144   void Stop() {
145     ASSERT_TRUE(!!stream_);
146     stream_->Stop();
147   }
148
149   void Close() {
150     ASSERT_TRUE(!!stream_);
151     stream_->Close();
152     stream_ = NULL;
153     closed_stream_.Signal();
154   }
155
156   void WaitForDataToFlow() {
157     // Wait until audio thread is idle before calling output_streams_.size().
158     SyncWithAudioThread();
159
160     const int count = output_streams_.size();
161     for (int i = 0; i < count; ++i) {
162       source_.WaitForDataPulls();
163     }
164
165     input_callback_.WaitForDataPushes();
166   }
167
168   void WaitUntilClosed() {
169     closed_stream_.Wait();
170   }
171
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();
177
178     output_stream->Stop();
179     output_stream->Close();
180   }
181
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);
189   }
190
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();
196     }
197   }
198
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);
205     }
206     stopped_output_streams_.clear();
207   }
208
209   const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
210     return audio_task_runner_;
211   }
212
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();
219       }
220       return worker_task_runner_;
221     } else {
222       return audio_task_runner_;
223     }
224   }
225
226  private:
227   void SyncWithAudioThread() {
228     base::WaitableEvent done(false, false);
229     audio_task_runner_->PostTask(
230         FROM_HERE,
231         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
232     done.Wait();
233   }
234
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_;
239
240   VirtualAudioInputStream* stream_;
241   MockInputCallback input_callback_;
242   base::WaitableEvent closed_stream_;
243
244   std::list<AudioOutputStream*> output_streams_;
245   std::list<AudioOutputStream*> stopped_output_streams_;
246   TestAudioSource source_;
247
248   DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
249 };
250
251 #define RUN_ON_AUDIO_THREAD(method)  \
252   audio_task_runner()->PostTask(  \
253       FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
254                             base::Unretained(this)))
255
256 TEST_P(VirtualAudioInputStreamTest, CreateAndClose) {
257   RUN_ON_AUDIO_THREAD(Create);
258   RUN_ON_AUDIO_THREAD(Close);
259   WaitUntilClosed();
260 }
261
262 TEST_P(VirtualAudioInputStreamTest, NoOutputs) {
263   RUN_ON_AUDIO_THREAD(Create);
264   RUN_ON_AUDIO_THREAD(Start);
265   WaitForDataToFlow();
266   RUN_ON_AUDIO_THREAD(Stop);
267   RUN_ON_AUDIO_THREAD(Close);
268   WaitUntilClosed();
269 }
270
271 TEST_P(VirtualAudioInputStreamTest, SingleOutput) {
272   RUN_ON_AUDIO_THREAD(Create);
273   RUN_ON_AUDIO_THREAD(Start);
274   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
275   WaitForDataToFlow();
276   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
277   RUN_ON_AUDIO_THREAD(Stop);
278   RUN_ON_AUDIO_THREAD(Close);
279   WaitUntilClosed();
280 }
281
282 TEST_P(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
283   RUN_ON_AUDIO_THREAD(Create);
284   RUN_ON_AUDIO_THREAD(Start);
285   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
286   WaitForDataToFlow();
287   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
288   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
289   WaitForDataToFlow();
290   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
291   RUN_ON_AUDIO_THREAD(Stop);
292   RUN_ON_AUDIO_THREAD(Close);
293   WaitUntilClosed();
294 }
295
296 TEST_P(VirtualAudioInputStreamTest, MultipleOutputs) {
297   RUN_ON_AUDIO_THREAD(Create);
298   RUN_ON_AUDIO_THREAD(Start);
299   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
300   WaitForDataToFlow();
301   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
302   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
303   WaitForDataToFlow();
304   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
305   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
306   WaitForDataToFlow();
307   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
308   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
309   WaitForDataToFlow();
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);
315   WaitUntilClosed();
316 }
317
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;
323
324   RUN_ON_AUDIO_THREAD(Create);
325   for (int i = 0; i < kHalfNumOutputs; ++i) {
326     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
327   }
328   RUN_ON_AUDIO_THREAD(Start);
329   WaitForDataToFlow();
330   for (int i = 0; i < kHalfNumOutputs; ++i) {
331     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
332   }
333   WaitForDataToFlow();
334   for (int i = 0; i < kPauseIterations; ++i) {
335     RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
336     WaitForDataToFlow();
337     RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
338     WaitForDataToFlow();
339   }
340   for (int i = 0; i < kHalfNumOutputs; ++i) {
341     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
342   }
343   RUN_ON_AUDIO_THREAD(Stop);
344   for (int i = 0; i < kHalfNumOutputs; ++i) {
345     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
346   }
347   RUN_ON_AUDIO_THREAD(Close);
348   WaitUntilClosed();
349 }
350
351 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded,
352                         VirtualAudioInputStreamTest,
353                         ::testing::Values(false, true));
354
355 }  // namespace media