virtual_audio_input_stream_unittest.cc revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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/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"
19
20using ::testing::_;
21using ::testing::AtLeast;
22using ::testing::InvokeWithoutArgs;
23using ::testing::NotNull;
24
25namespace media {
26
27namespace {
28
29const AudioParameters kParams(
30    AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_STEREO, 8000, 8, 10);
31
32class MockInputCallback : public AudioInputStream::AudioInputCallback {
33 public:
34  MockInputCallback()
35      : data_pushed_(false, false) {
36    ON_CALL(*this, OnData(_, _, _, _, _))
37        .WillByDefault(InvokeWithoutArgs(&data_pushed_,
38                                         &base::WaitableEvent::Signal));
39  }
40
41  virtual ~MockInputCallback() {}
42
43  MOCK_METHOD5(OnData, void(AudioInputStream* stream, const uint8* data,
44                            uint32 size, uint32 hardware_delay_bytes,
45                            double volume));
46  MOCK_METHOD1(OnClose, void(AudioInputStream* stream));
47  MOCK_METHOD1(OnError, void(AudioInputStream* stream));
48
49  void WaitForDataPushes() {
50    for (int i = 0; i < 3; ++i) {
51      data_pushed_.Wait();
52    }
53  }
54
55 private:
56  base::WaitableEvent data_pushed_;
57
58  DISALLOW_COPY_AND_ASSIGN(MockInputCallback);
59};
60
61class TestAudioSource : public SineWaveAudioSource {
62 public:
63  TestAudioSource()
64      : SineWaveAudioSource(
65            kParams.channel_layout(), 200.0, kParams.sample_rate()),
66        data_pulled_(false, false) {}
67
68  virtual ~TestAudioSource() {}
69
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();
74    return ret;
75  }
76
77  virtual int OnMoreIOData(AudioBus* source,
78                           AudioBus* dest,
79                           AudioBuffersState audio_buffers) OVERRIDE {
80    const int ret =
81        SineWaveAudioSource::OnMoreIOData(source, dest, audio_buffers);
82    data_pulled_.Signal();
83    return ret;
84  }
85
86  void WaitForDataPulls() {
87    for (int i = 0; i < 3; ++i) {
88      data_pulled_.Wait();
89    }
90  }
91
92 private:
93  base::WaitableEvent data_pulled_;
94
95  DISALLOW_COPY_AND_ASSIGN(TestAudioSource);
96};
97
98}  // namespace
99
100class VirtualAudioInputStreamTest : public testing::Test {
101 public:
102  VirtualAudioInputStreamTest()
103      : audio_thread_(new base::Thread("AudioThread")),
104        stream_(NULL),
105        closed_stream_(false, false) {
106    audio_thread_->Start();
107    audio_message_loop_ = audio_thread_->message_loop_proxy();
108  }
109
110  virtual ~VirtualAudioInputStreamTest() {
111    SyncWithAudioThread();
112
113    DCHECK(output_streams_.empty());
114    DCHECK(stopped_output_streams_.empty());
115  }
116
117  void Create() {
118    stream_ = new VirtualAudioInputStream(
119        kParams, audio_message_loop_,
120        base::Bind(&base::DeletePointer<VirtualAudioInputStream>));
121    stream_->Open();
122  }
123
124  void Start() {
125    EXPECT_CALL(input_callback_, OnClose(_));
126    EXPECT_CALL(input_callback_, OnData(_, NotNull(), _, _, _))
127        .Times(AtLeast(1));
128
129    ASSERT_TRUE(!!stream_);
130    stream_->Start(&input_callback_);
131  }
132
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);
140
141    output_stream->Open();
142    output_stream->Start(&source_);
143  }
144
145  void Stop() {
146    ASSERT_TRUE(!!stream_);
147    stream_->Stop();
148  }
149
150  void Close() {
151    ASSERT_TRUE(!!stream_);
152    stream_->Close();
153    stream_ = NULL;
154    closed_stream_.Signal();
155  }
156
157  void WaitForDataToFlow() {
158    // Wait until audio thread is idle before calling output_streams_.size().
159    SyncWithAudioThread();
160
161    const int count = output_streams_.size();
162    for (int i = 0; i < count; ++i) {
163      source_.WaitForDataPulls();
164    }
165
166    input_callback_.WaitForDataPushes();
167  }
168
169  void WaitUntilClosed() {
170    closed_stream_.Wait();
171  }
172
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();
178
179    output_stream->Stop();
180    output_stream->Close();
181  }
182
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);
190  }
191
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();
197    }
198  }
199
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);
206    }
207    stopped_output_streams_.clear();
208  }
209
210  const scoped_refptr<base::MessageLoopProxy>& audio_message_loop() const {
211    return audio_message_loop_;
212  }
213
214 private:
215  void SyncWithAudioThread() {
216    base::WaitableEvent done(false, false);
217    audio_message_loop_->PostTask(
218        FROM_HERE,
219        base::Bind(&base::WaitableEvent::Signal, base::Unretained(&done)));
220    done.Wait();
221  }
222
223  scoped_ptr<base::Thread> audio_thread_;
224  scoped_refptr<base::MessageLoopProxy> audio_message_loop_;
225
226  VirtualAudioInputStream* stream_;
227  MockInputCallback input_callback_;
228  base::WaitableEvent closed_stream_;
229
230  std::list<AudioOutputStream*> output_streams_;
231  std::list<AudioOutputStream*> stopped_output_streams_;
232  TestAudioSource source_;
233
234  DISALLOW_COPY_AND_ASSIGN(VirtualAudioInputStreamTest);
235};
236
237#define RUN_ON_AUDIO_THREAD(method)  \
238  audio_message_loop()->PostTask(  \
239      FROM_HERE, base::Bind(&VirtualAudioInputStreamTest::method,  \
240                            base::Unretained(this)))
241
242TEST_F(VirtualAudioInputStreamTest, CreateAndClose) {
243  RUN_ON_AUDIO_THREAD(Create);
244  RUN_ON_AUDIO_THREAD(Close);
245  WaitUntilClosed();
246}
247
248TEST_F(VirtualAudioInputStreamTest, NoOutputs) {
249  RUN_ON_AUDIO_THREAD(Create);
250  RUN_ON_AUDIO_THREAD(Start);
251  WaitForDataToFlow();
252  RUN_ON_AUDIO_THREAD(Stop);
253  RUN_ON_AUDIO_THREAD(Close);
254  WaitUntilClosed();
255}
256
257TEST_F(VirtualAudioInputStreamTest, SingleOutput) {
258  RUN_ON_AUDIO_THREAD(Create);
259  RUN_ON_AUDIO_THREAD(Start);
260  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
261  WaitForDataToFlow();
262  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
263  RUN_ON_AUDIO_THREAD(Stop);
264  RUN_ON_AUDIO_THREAD(Close);
265  WaitUntilClosed();
266}
267
268TEST_F(VirtualAudioInputStreamTest, SingleOutputPausedAndRestarted) {
269  RUN_ON_AUDIO_THREAD(Create);
270  RUN_ON_AUDIO_THREAD(Start);
271  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
272  WaitForDataToFlow();
273  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
274  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
275  WaitForDataToFlow();
276  RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
277  RUN_ON_AUDIO_THREAD(Stop);
278  RUN_ON_AUDIO_THREAD(Close);
279  WaitUntilClosed();
280}
281
282TEST_F(VirtualAudioInputStreamTest, MultipleOutputs) {
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(CreateAndStartOneOutputStream);
288  RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
289  WaitForDataToFlow();
290  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
291  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
292  WaitForDataToFlow();
293  RUN_ON_AUDIO_THREAD(StopFirstOutputStream);
294  RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
295  WaitForDataToFlow();
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);
301  WaitUntilClosed();
302}
303
304// A combination of all of the above tests with many output streams.
305TEST_F(VirtualAudioInputStreamTest, ComprehensiveTest) {
306  static const int kNumOutputs = 8;
307  static const int kHalfNumOutputs = kNumOutputs / 2;
308  static const int kPauseIterations = 5;
309
310  RUN_ON_AUDIO_THREAD(Create);
311  for (int i = 0; i < kHalfNumOutputs; ++i) {
312    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
313  }
314  RUN_ON_AUDIO_THREAD(Start);
315  WaitForDataToFlow();
316  for (int i = 0; i < kHalfNumOutputs; ++i) {
317    RUN_ON_AUDIO_THREAD(CreateAndStartOneOutputStream);
318  }
319  WaitForDataToFlow();
320  for (int i = 0; i < kPauseIterations; ++i) {
321    RUN_ON_AUDIO_THREAD(StopSomeOutputStreams);
322    WaitForDataToFlow();
323    RUN_ON_AUDIO_THREAD(RestartAllStoppedOutputStreams);
324    WaitForDataToFlow();
325  }
326  for (int i = 0; i < kHalfNumOutputs; ++i) {
327    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
328  }
329  RUN_ON_AUDIO_THREAD(Stop);
330  for (int i = 0; i < kHalfNumOutputs; ++i) {
331    RUN_ON_AUDIO_THREAD(StopAndCloseOneOutputStream);
332  }
333  RUN_ON_AUDIO_THREAD(Close);
334  WaitUntilClosed();
335}
336
337}  // namespace media
338