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/basictypes.h"
6#include "base/environment.h"
7#include "base/memory/scoped_ptr.h"
8#include "base/message_loop/message_loop.h"
9#include "base/run_loop.h"
10#include "base/synchronization/waitable_event.h"
11#include "base/threading/platform_thread.h"
12#include "media/audio/audio_io.h"
13#include "media/audio/audio_manager_base.h"
14#include "testing/gtest/include/gtest/gtest.h"
15
16namespace media {
17
18// This class allows to find out if the callbacks are occurring as
19// expected and if any error has been reported.
20class TestInputCallback : public AudioInputStream::AudioInputCallback {
21 public:
22  explicit TestInputCallback()
23      : callback_count_(0),
24        had_error_(0) {
25  }
26  virtual void OnData(AudioInputStream* stream,
27                      const AudioBus* source,
28                      uint32 hardware_delay_bytes,
29                      double volume) OVERRIDE {
30    ++callback_count_;
31  }
32  virtual void OnError(AudioInputStream* stream) OVERRIDE {
33    ++had_error_;
34  }
35  // Returns how many times OnData() has been called.
36  int callback_count() const {
37    return callback_count_;
38  }
39  // Returns how many times the OnError callback was called.
40  int had_error() const {
41    return had_error_;
42  }
43
44 private:
45  int callback_count_;
46  int had_error_;
47};
48
49class AudioInputTest : public testing::Test {
50  public:
51   AudioInputTest() :
52      message_loop_(base::MessageLoop::TYPE_UI),
53      audio_manager_(AudioManager::CreateForTesting()),
54      audio_input_stream_(NULL) {
55    // Wait for the AudioManager to finish any initialization on the audio loop.
56    base::RunLoop().RunUntilIdle();
57  }
58
59  virtual ~AudioInputTest() {
60    base::RunLoop().RunUntilIdle();
61  }
62
63 protected:
64  AudioManager* audio_manager() { return audio_manager_.get(); }
65
66  bool CanRunAudioTests() {
67    bool has_input = audio_manager()->HasAudioInputDevices();
68    LOG_IF(WARNING, !has_input) << "No input devices detected";
69    return has_input;
70  }
71
72  void MakeAudioInputStreamOnAudioThread() {
73    RunOnAudioThread(
74        base::Bind(&AudioInputTest::MakeAudioInputStream,
75                   base::Unretained(this)));
76  }
77
78  void CloseAudioInputStreamOnAudioThread() {
79    RunOnAudioThread(
80        base::Bind(&AudioInputStream::Close,
81                   base::Unretained(audio_input_stream_)));
82    audio_input_stream_ = NULL;
83  }
84
85  void OpenAndCloseAudioInputStreamOnAudioThread() {
86    RunOnAudioThread(
87        base::Bind(&AudioInputTest::OpenAndClose,
88                   base::Unretained(this)));
89  }
90
91  void OpenStopAndCloseAudioInputStreamOnAudioThread() {
92    RunOnAudioThread(
93        base::Bind(&AudioInputTest::OpenStopAndClose,
94                   base::Unretained(this)));
95  }
96
97  void OpenAndStartAudioInputStreamOnAudioThread(
98      AudioInputStream::AudioInputCallback* sink) {
99    RunOnAudioThread(
100        base::Bind(&AudioInputTest::OpenAndStart,
101                   base::Unretained(this),
102                   sink));
103  }
104
105  void StopAndCloseAudioInputStreamOnAudioThread() {
106    RunOnAudioThread(
107        base::Bind(&AudioInputTest::StopAndClose,
108                   base::Unretained(this)));
109  }
110
111  void MakeAudioInputStream() {
112    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
113    AudioParameters params = audio_manager()->GetInputStreamParameters(
114        AudioManagerBase::kDefaultDeviceId);
115    audio_input_stream_ = audio_manager()->MakeAudioInputStream(params,
116        AudioManagerBase::kDefaultDeviceId);
117    EXPECT_TRUE(audio_input_stream_);
118  }
119
120  void OpenAndClose() {
121    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
122    EXPECT_TRUE(audio_input_stream_->Open());
123    audio_input_stream_->Close();
124    audio_input_stream_ = NULL;
125  }
126
127  void OpenAndStart(AudioInputStream::AudioInputCallback* sink) {
128    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
129    EXPECT_TRUE(audio_input_stream_->Open());
130    audio_input_stream_->Start(sink);
131  }
132
133  void OpenStopAndClose() {
134    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
135    EXPECT_TRUE(audio_input_stream_->Open());
136    audio_input_stream_->Stop();
137    audio_input_stream_->Close();
138    audio_input_stream_ = NULL;
139  }
140
141  void StopAndClose() {
142    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
143    audio_input_stream_->Stop();
144    audio_input_stream_->Close();
145    audio_input_stream_ = NULL;
146  }
147
148  // Synchronously runs the provided callback/closure on the audio thread.
149  void RunOnAudioThread(const base::Closure& closure) {
150    if (!audio_manager()->GetTaskRunner()->BelongsToCurrentThread()) {
151      base::WaitableEvent event(false, false);
152      audio_manager()->GetTaskRunner()->PostTask(
153          FROM_HERE,
154          base::Bind(&AudioInputTest::RunOnAudioThreadImpl,
155                     base::Unretained(this),
156                     closure,
157                     &event));
158      event.Wait();
159    } else {
160      closure.Run();
161    }
162  }
163
164  void RunOnAudioThreadImpl(const base::Closure& closure,
165                            base::WaitableEvent* event) {
166    DCHECK(audio_manager()->GetTaskRunner()->BelongsToCurrentThread());
167    closure.Run();
168    event->Signal();
169  }
170
171  base::MessageLoop message_loop_;
172  scoped_ptr<AudioManager> audio_manager_;
173  AudioInputStream* audio_input_stream_;
174
175 private:
176  DISALLOW_COPY_AND_ASSIGN(AudioInputTest);
177};
178
179// Test create and close of an AudioInputStream without recording audio.
180TEST_F(AudioInputTest, CreateAndClose) {
181  if (!CanRunAudioTests())
182    return;
183  MakeAudioInputStreamOnAudioThread();
184  CloseAudioInputStreamOnAudioThread();
185}
186
187#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
188// This test is failing on ARM linux: http://crbug.com/238490
189#define MAYBE_OpenAndClose DISABLED_OpenAndClose
190#else
191#define MAYBE_OpenAndClose OpenAndClose
192#endif
193// Test create, open and close of an AudioInputStream without recording audio.
194TEST_F(AudioInputTest, MAYBE_OpenAndClose) {
195  if (!CanRunAudioTests())
196    return;
197  MakeAudioInputStreamOnAudioThread();
198  OpenAndCloseAudioInputStreamOnAudioThread();
199}
200
201#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
202// This test is failing on ARM linux: http://crbug.com/238490
203#define MAYBE_OpenStopAndClose DISABLED_OpenStopAndClose
204#else
205#define MAYBE_OpenStopAndClose OpenStopAndClose
206#endif
207// Test create, open, stop and close of an AudioInputStream without recording.
208TEST_F(AudioInputTest, MAYBE_OpenStopAndClose) {
209  if (!CanRunAudioTests())
210    return;
211  MakeAudioInputStreamOnAudioThread();
212  OpenStopAndCloseAudioInputStreamOnAudioThread();
213}
214
215#if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(ARCH_CPU_ARM_FAMILY)
216// This test is failing on ARM linux: http://crbug.com/238490
217#define MAYBE_Record DISABLED_Record
218#else
219#define MAYBE_Record Record
220#endif
221// Test a normal recording sequence using an AudioInputStream.
222// Very simple test which starts capturing during half a second and verifies
223// that recording starts.
224TEST_F(AudioInputTest, MAYBE_Record) {
225  if (!CanRunAudioTests())
226    return;
227  MakeAudioInputStreamOnAudioThread();
228
229  TestInputCallback test_callback;
230  OpenAndStartAudioInputStreamOnAudioThread(&test_callback);
231
232  message_loop_.PostDelayedTask(
233      FROM_HERE,
234      base::MessageLoop::QuitClosure(),
235      base::TimeDelta::FromMilliseconds(500));
236  message_loop_.Run();
237  EXPECT_GE(test_callback.callback_count(), 2);
238  EXPECT_FALSE(test_callback.had_error());
239
240  StopAndCloseAudioInputStreamOnAudioThread();
241}
242
243}  // namespace media
244