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.
5 #include "base/basictypes.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/test/test_timeouts.h"
10 #include "media/audio/audio_input_controller.h"
11 #include "media/audio/audio_manager_base.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
16 using ::testing::AtLeast;
17 using ::testing::Exactly;
18 using ::testing::InvokeWithoutArgs;
19 using ::testing::NotNull;
23 static const int kSampleRate = AudioParameters::kAudioCDSampleRate;
24 static const int kBitsPerSample = 16;
25 static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
26 static const int kSamplesPerPacket = kSampleRate / 10;
28 // Posts base::MessageLoop::QuitClosure() on specified message loop.
29 ACTION_P(QuitMessageLoop, loop_or_proxy) {
30 loop_or_proxy->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
33 // Posts base::MessageLoop::QuitClosure() on specified message loop after a
34 // certain number of calls given by |limit|.
35 ACTION_P3(CheckCountAndPostQuitTask, count, limit, loop_or_proxy) {
36 if (++*count >= limit) {
37 loop_or_proxy->PostTask(FROM_HERE, base::MessageLoop::QuitClosure());
41 // Closes AudioOutputController synchronously.
42 static void CloseAudioController(AudioInputController* controller) {
43 controller->Close(base::MessageLoop::QuitClosure());
44 base::MessageLoop::current()->Run();
47 class MockAudioInputControllerEventHandler
48 : public AudioInputController::EventHandler {
50 MockAudioInputControllerEventHandler() {}
52 MOCK_METHOD1(OnCreated, void(AudioInputController* controller));
53 MOCK_METHOD1(OnRecording, void(AudioInputController* controller));
54 MOCK_METHOD2(OnError, void(AudioInputController* controller,
55 AudioInputController::ErrorCode error_code));
56 MOCK_METHOD3(OnData, void(AudioInputController* controller,
57 const uint8* data, uint32 size));
60 DISALLOW_COPY_AND_ASSIGN(MockAudioInputControllerEventHandler);
64 class AudioInputControllerTest : public testing::Test {
66 AudioInputControllerTest() {}
67 virtual ~AudioInputControllerTest() {}
70 base::MessageLoop message_loop_;
73 DISALLOW_COPY_AND_ASSIGN(AudioInputControllerTest);
76 // Test AudioInputController for create and close without recording audio.
77 TEST_F(AudioInputControllerTest, CreateAndClose) {
78 MockAudioInputControllerEventHandler event_handler;
80 // OnCreated() will be posted once.
81 EXPECT_CALL(event_handler, OnCreated(NotNull()))
82 .WillOnce(QuitMessageLoop(&message_loop_));
84 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
85 AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
86 kSampleRate, kBitsPerSample, kSamplesPerPacket);
88 scoped_refptr<AudioInputController> controller =
89 AudioInputController::Create(audio_manager.get(),
92 AudioManagerBase::kDefaultDeviceId,
94 ASSERT_TRUE(controller.get());
96 // Wait for OnCreated() to fire.
99 // Close the AudioInputController synchronously.
100 CloseAudioController(controller.get());
103 // Test a normal call sequence of create, record and close.
104 TEST_F(AudioInputControllerTest, RecordAndClose) {
105 MockAudioInputControllerEventHandler event_handler;
108 // OnCreated() will be called once.
109 EXPECT_CALL(event_handler, OnCreated(NotNull()))
112 // OnRecording() will be called only once.
113 EXPECT_CALL(event_handler, OnRecording(NotNull()))
116 // OnData() shall be called ten times.
117 EXPECT_CALL(event_handler, OnData(NotNull(), NotNull(), _))
119 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10,
120 message_loop_.message_loop_proxy()));
122 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
123 AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
124 kSampleRate, kBitsPerSample, kSamplesPerPacket);
126 // Creating the AudioInputController should render an OnCreated() call.
127 scoped_refptr<AudioInputController> controller =
128 AudioInputController::Create(audio_manager.get(),
131 AudioManagerBase::kDefaultDeviceId,
133 ASSERT_TRUE(controller.get());
135 // Start recording and trigger one OnRecording() call.
136 controller->Record();
138 // Record and wait until ten OnData() callbacks are received.
141 // Close the AudioInputController synchronously.
142 CloseAudioController(controller.get());
145 // Test that the AudioInputController reports an error when the input stream
146 // stops. This can happen when the underlying audio layer stops feeding data as
147 // a result of a removed microphone device.
148 #if defined(OS_MACOSX)
149 // Disabled on Mac due to crbug.com/357501.
150 // TODO(tommi): Remove the test when the timer workaround has been removed.
151 #define MAYBE_RecordAndError DISABLED_RecordAndError
153 #define MAYBE_RecordAndError RecordAndError
155 TEST_F(AudioInputControllerTest, MAYBE_RecordAndError) {
156 MockAudioInputControllerEventHandler event_handler;
159 // OnCreated() will be called once.
160 EXPECT_CALL(event_handler, OnCreated(NotNull()))
163 // OnRecording() will be called only once.
164 EXPECT_CALL(event_handler, OnRecording(NotNull()))
167 // OnData() shall be called ten times.
168 EXPECT_CALL(event_handler, OnData(NotNull(), NotNull(), _))
170 .WillRepeatedly(CheckCountAndPostQuitTask(&count, 10,
171 message_loop_.message_loop_proxy()));
173 // OnError() will be called after the data stream stops while the
174 // controller is in a recording state.
175 EXPECT_CALL(event_handler, OnError(NotNull(),
176 AudioInputController::NO_DATA_ERROR))
178 .WillOnce(QuitMessageLoop(&message_loop_));
180 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
181 AudioParameters params(AudioParameters::AUDIO_FAKE, kChannelLayout,
182 kSampleRate, kBitsPerSample, kSamplesPerPacket);
184 // Creating the AudioInputController should render an OnCreated() call.
185 scoped_refptr<AudioInputController> controller =
186 AudioInputController::Create(audio_manager.get(),
189 AudioManagerBase::kDefaultDeviceId,
191 ASSERT_TRUE(controller.get());
193 // Start recording and trigger one OnRecording() call.
194 controller->Record();
196 // Record and wait until ten OnData() callbacks are received.
199 // Stop the stream and verify that OnError() is posted.
200 AudioInputStream* stream = controller->stream_for_testing();
204 // Close the AudioInputController synchronously.
205 CloseAudioController(controller.get());
208 // Test that AudioInputController rejects insanely large packet sizes.
209 TEST_F(AudioInputControllerTest, SamplesPerPacketTooLarge) {
210 // Create an audio device with a very large packet size.
211 MockAudioInputControllerEventHandler event_handler;
213 // OnCreated() shall not be called in this test.
214 EXPECT_CALL(event_handler, OnCreated(NotNull()))
217 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
218 AudioParameters params(AudioParameters::AUDIO_FAKE,
222 kSamplesPerPacket * 1000);
223 scoped_refptr<AudioInputController> controller =
224 AudioInputController::Create(audio_manager.get(),
227 AudioManagerBase::kDefaultDeviceId,
229 ASSERT_FALSE(controller.get());
232 // Test calling AudioInputController::Close multiple times.
233 TEST_F(AudioInputControllerTest, CloseTwice) {
234 MockAudioInputControllerEventHandler event_handler;
236 // OnRecording() will be called only once.
237 EXPECT_CALL(event_handler, OnCreated(NotNull()));
239 // OnRecording() will be called only once.
240 EXPECT_CALL(event_handler, OnRecording(NotNull()))
243 scoped_ptr<AudioManager> audio_manager(AudioManager::CreateForTesting());
244 AudioParameters params(AudioParameters::AUDIO_FAKE,
249 scoped_refptr<AudioInputController> controller =
250 AudioInputController::Create(audio_manager.get(),
253 AudioManagerBase::kDefaultDeviceId,
255 ASSERT_TRUE(controller.get());
257 controller->Record();
259 controller->Close(base::MessageLoop::QuitClosure());
260 base::MessageLoop::current()->Run();
262 controller->Close(base::MessageLoop::QuitClosure());
263 base::MessageLoop::current()->Run();