Update To 11.40.268.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(_, _, _, _)).WillByDefault(
36         InvokeWithoutArgs(&data_pushed_, &base::WaitableEvent::Signal));
37   }
38
39   virtual ~MockInputCallback() {}
40
41   MOCK_METHOD4(OnData,
42                void(AudioInputStream* stream,
43                     const AudioBus* source,
44                     uint32 hardware_delay_bytes,
45                     double volume));
46   MOCK_METHOD1(OnError, void(AudioInputStream* stream));
47
48   void WaitForDataPushes() {
49     for (int i = 0; i < 3; ++i) {
50       data_pushed_.Wait();
51     }
52   }
53
54  private:
55   base::WaitableEvent data_pushed_;
56
57   DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
58 };
59
60 class TestAudioSource : public SineWaveAudioSource {
61  public:
62   TestAudioSource()
63       : SineWaveAudioSource(
64             kParams.channel_layout(), 200.0, kParams.sample_rate()),
65         data_pulled_(false, false) {}
66
67   ~TestAudioSource() override {}
68
69   int OnMoreData(AudioBus* audio_bus, uint32 total_bytes_delay) override {
70     const int ret = SineWaveAudioSource::OnMoreData(audio_bus,
71                                                     total_bytes_delay);
72     data_pulled_.Signal();
73     return ret;
74   }
75
76   void WaitForDataPulls() {
77     for (int i = 0; i < 3; ++i) {
78       data_pulled_.Wait();
79     }
80   }
81
82  private:
83   base::WaitableEvent data_pulled_;
84
85   DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
86 };
87
88 }  // namespace
89
90 class VirtualAudioInputStreamTest : public testing::TestWithParam<bool> {
91  public:
92   VirtualAudioInputStreamTest()
93       : audio_thread_(new base::Thread("AudioThread")),
94         worker_thread_(new base::Thread("AudioWorkerThread")),
95         stream_(NULL),
96         closed_stream_(false, false) {
97     audio_thread_->Start();
98     audio_task_runner_ = audio_thread_->message_loop_proxy();
99   }
100
101   virtual ~VirtualAudioInputStreamTest() {
102     SyncWithAudioThread();
103
104     DCHECK(output_streams_.empty());
105     DCHECK(stopped_output_streams_.empty());
106   }
107
108   void Create() {
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>));
113     stream_->Open();
114   }
115
116   void Start() {
117     EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _)).Times(AtLeast(1));
118
119     ASSERT_TRUE(!!stream_);
120     stream_->Start(&input_callback_);
121   }
122
123   void CreateAndStartOneOutputStream() {
124     ASSERT_TRUE(!!stream_);
125     AudioOutputStream* const output_stream = new VirtualAudioOutputStream(
126         kParams,
127         stream_,
128         base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
129     output_streams_.push_back(output_stream);
130
131     output_stream->Open();
132     output_stream->Start(&source_);
133   }
134
135   void Stop() {
136     ASSERT_TRUE(!!stream_);
137     stream_->Stop();
138   }
139
140   void Close() {
141     ASSERT_TRUE(!!stream_);
142     stream_->Close();
143     stream_ = NULL;
144     closed_stream_.Signal();
145   }
146
147   void WaitForDataToFlow() {
148     // Wait until audio thread is idle before calling output_streams_.size().
149     SyncWithAudioThread();
150
151     const int count = output_streams_.size();
152     for (int i = 0; i < count; ++i) {
153       source_.WaitForDataPulls();
154     }
155
156     input_callback_.WaitForDataPushes();
157   }
158
159   void WaitUntilClosed() {
160     closed_stream_.Wait();
161   }
162
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();
168
169     output_stream->Stop();
170     output_stream->Close();
171   }
172
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);
180   }
181
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();
187     }
188   }
189
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);
196     }
197     stopped_output_streams_.clear();
198   }
199
200   const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
201     return audio_task_runner_;
202   }
203
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_->message_loop_proxy();
210       }
211       return worker_task_runner_;
212     } else {
213       return audio_task_runner_;
214     }
215   }
216
217  private:
218   void SyncWithAudioThread() {
219     base::WaitableEvent done(false, false);
220     audio_task_runner_->PostTask(
221         FROM_HERE,
222         base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
223     done.Wait();
224   }
225
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_;
230
231   VirtualAudioInputStream* stream_;
232   MockInputCallback input_callback_;
233   base::WaitableEvent closed_stream_;
234
235   std::list<AudioOutputStream*> output_streams_;
236   std::list<AudioOutputStream*> stopped_output_streams_;
237   TestAudioSource source_;
238
239   DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
240 };
241
242 #define RUN_ON_AUDIO_THREAD(method)  \
243   audio_task_runner()->PostTask(  \
244       FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
245                             base::Unretained(this)))
246
247 TEST_P(VirtualAudioInputStreamTest, CreateAndClose) {
248   RUN_ON_AUDIO_THREAD(Create);
249   RUN_ON_AUDIO_THREAD(Close);
250   WaitUntilClosed();
251 }
252
253 TEST_P(VirtualAudioInputStreamTest, NoOutputs) {
254   RUN_ON_AUDIO_THREAD(Create);
255   RUN_ON_AUDIO_THREAD(Start);
256   WaitForDataToFlow();
257   RUN_ON_AUDIO_THREAD(Stop);
258   RUN_ON_AUDIO_THREAD(Close);
259   WaitUntilClosed();
260 }
261
262 TEST_P(VirtualAudioInputStreamTest, SingleOutput) {
263   RUN_ON_AUDIO_THREAD(Create);
264   RUN_ON_AUDIO_THREAD(Start);
265   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
266   WaitForDataToFlow();
267   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
268   RUN_ON_AUDIO_THREAD(Stop);
269   RUN_ON_AUDIO_THREAD(Close);
270   WaitUntilClosed();
271 }
272
273 TEST_P(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
274   RUN_ON_AUDIO_THREAD(Create);
275   RUN_ON_AUDIO_THREAD(Start);
276   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
277   WaitForDataToFlow();
278   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
279   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
280   WaitForDataToFlow();
281   RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
282   RUN_ON_AUDIO_THREAD(Stop);
283   RUN_ON_AUDIO_THREAD(Close);
284   WaitUntilClosed();
285 }
286
287 TEST_P(VirtualAudioInputStreamTest, MultipleOutputs) {
288   RUN_ON_AUDIO_THREAD(Create);
289   RUN_ON_AUDIO_THREAD(Start);
290   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
291   WaitForDataToFlow();
292   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
293   RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
294   WaitForDataToFlow();
295   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
296   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
297   WaitForDataToFlow();
298   RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
299   RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
300   WaitForDataToFlow();
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);
306   WaitUntilClosed();
307 }
308
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;
314
315   RUN_ON_AUDIO_THREAD(Create);
316   for (int i = 0; i < kHalfNumOutputs; ++i) {
317     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
318   }
319   RUN_ON_AUDIO_THREAD(Start);
320   WaitForDataToFlow();
321   for (int i = 0; i < kHalfNumOutputs; ++i) {
322     RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
323   }
324   WaitForDataToFlow();
325   for (int i = 0; i < kPauseIterations; ++i) {
326     RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
327     WaitForDataToFlow();
328     RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
329     WaitForDataToFlow();
330   }
331   for (int i = 0; i < kHalfNumOutputs; ++i) {
332     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
333   }
334   RUN_ON_AUDIO_THREAD(Stop);
335   for (int i = 0; i < kHalfNumOutputs; ++i) {
336     RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
337   }
338   RUN_ON_AUDIO_THREAD(Close);
339   WaitUntilClosed();
340 }
341
342 INSTANTIATE_TEST_CASE_P(SingleVersusMultithreaded,
343                         VirtualAudioInputStreamTest,
344                         ::testing::Values(false, true));
345
346 }  // namespace media