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 "base/bind.h"
6#include "base/bind_helpers.h"
7#include "base/synchronization/waitable_event.h"
8#include "base/threading/thread.h"
9#include "media/audio/audio_manager.h"
10#include "media/audio/simple_sources.h"
11#include "media/audio/virtual_audio_input_stream.h"
12#include "media/audio/virtual_audio_output_stream.h"
13#include "testing/gmock/include/gmock/gmock.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16using ::testing::_;
17
18namespace media {
19
20namespace {
21const AudioParameters kParams(
22    AudioParameters::AUDIO_PCM_LOW_LATENCY, CHANNEL_LAYOUT_MONO, 8000, 8, 128);
23}
24
25class MockVirtualAudioInputStream : public VirtualAudioInputStream {
26 public:
27  explicit MockVirtualAudioInputStream(
28      const scoped_refptr<base::SingleThreadTaskRunner>& worker_task_runner)
29      : VirtualAudioInputStream(
30            kParams,
31            worker_task_runner,
32            base::Bind(&base::DeletePointer<VirtualAudioInputStream>)) {}
33  ~MockVirtualAudioInputStream() {}
34
35  MOCK_METHOD2(AddOutputStream, void(VirtualAudioOutputStream* stream,
36                                     const AudioParameters& output_params));
37  MOCK_METHOD2(RemoveOutputStream, void(VirtualAudioOutputStream* stream,
38                                        const AudioParameters& output_params));
39
40 private:
41  DISALLOW_COPY_AND_ASSIGN(MockVirtualAudioInputStream);
42};
43
44class MockAudioDeviceListener : public AudioManager::AudioDeviceListener {
45 public:
46  MOCK_METHOD0(OnDeviceChange, void());
47};
48
49class VirtualAudioOutputStreamTest : public testing::Test {
50 public:
51  VirtualAudioOutputStreamTest()
52      : audio_thread_(new base::Thread("AudioThread")) {
53    audio_thread_->Start();
54    audio_task_runner_ = audio_thread_->message_loop_proxy();
55  }
56
57  const scoped_refptr<base::SingleThreadTaskRunner>& audio_task_runner() const {
58    return audio_task_runner_;
59  }
60
61  void SyncWithAudioThread() {
62    base::WaitableEvent done(false, false);
63    audio_task_runner()->PostTask(
64        FROM_HERE, base::Bind(&base::WaitableEvent::Signal,
65                              base::Unretained(&done)));
66    done.Wait();
67  }
68
69 private:
70  scoped_ptr<base::Thread> audio_thread_;
71  scoped_refptr<base::SingleThreadTaskRunner> audio_task_runner_;
72
73  DISALLOW_COPY_AND_ASSIGN(VirtualAudioOutputStreamTest);
74};
75
76TEST_F(VirtualAudioOutputStreamTest, StartStopStartStop) {
77  static const int kCycles = 3;
78
79  MockVirtualAudioInputStream* const input_stream =
80      new MockVirtualAudioInputStream(audio_task_runner());
81  audio_task_runner()->PostTask(
82      FROM_HERE, base::Bind(
83          base::IgnoreResult(&MockVirtualAudioInputStream::Open),
84          base::Unretained(input_stream)));
85
86  VirtualAudioOutputStream* const output_stream = new VirtualAudioOutputStream(
87      kParams,
88      input_stream,
89      base::Bind(&base::DeletePointer<VirtualAudioOutputStream>));
90
91  EXPECT_CALL(*input_stream, AddOutputStream(output_stream, _))
92      .Times(kCycles);
93  EXPECT_CALL(*input_stream, RemoveOutputStream(output_stream, _))
94      .Times(kCycles);
95
96  audio_task_runner()->PostTask(
97      FROM_HERE, base::Bind(base::IgnoreResult(&VirtualAudioOutputStream::Open),
98                            base::Unretained(output_stream)));
99  SineWaveAudioSource source(CHANNEL_LAYOUT_STEREO, 200.0, 128);
100  for (int i = 0; i < kCycles; ++i) {
101    audio_task_runner()->PostTask(
102        FROM_HERE, base::Bind(&VirtualAudioOutputStream::Start,
103                              base::Unretained(output_stream),
104                              &source));
105    audio_task_runner()->PostTask(
106        FROM_HERE, base::Bind(&VirtualAudioOutputStream::Stop,
107                              base::Unretained(output_stream)));
108  }
109  audio_task_runner()->PostTask(
110      FROM_HERE, base::Bind(&VirtualAudioOutputStream::Close,
111                            base::Unretained(output_stream)));
112
113  audio_task_runner()->PostTask(
114      FROM_HERE, base::Bind(&MockVirtualAudioInputStream::Close,
115                            base::Unretained(input_stream)));
116
117  SyncWithAudioThread();
118}
119
120}  // namespace media
121