1 // Copyright 2013 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/environment.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "media/audio/audio_manager.h"
9 #include "media/audio/audio_manager_base.h"
10 #include "media/audio/fake_audio_log_factory.h"
11 #include "testing/gtest/include/gtest/gtest.h"
12
13 #if defined(USE_ALSA)
14 #include "media/audio/alsa/audio_manager_alsa.h"
15 #endif // defined(USE_ALSA)
16
17 #if defined(OS_WIN)
18 #include "base/win/scoped_com_initializer.h"
19 #include "media/audio/win/audio_manager_win.h"
20 #include "media/audio/win/wavein_input_win.h"
21 #endif
22
23 #if defined(USE_PULSEAUDIO)
24 #include "media/audio/pulse/audio_manager_pulse.h"
25 #endif // defined(USE_PULSEAUDIO)
26
27 namespace media {
28
29 // Test fixture which allows us to override the default enumeration API on
30 // Windows.
31 class AudioManagerTest
32 : public ::testing::Test {
33 protected:
AudioManagerTest()34 AudioManagerTest()
35 : audio_manager_(AudioManager::CreateForTesting())
36 #if defined(OS_WIN)
37 , com_init_(base::win::ScopedCOMInitializer::kMTA)
38 #endif
39 {
40 }
41
42 #if defined(OS_WIN)
SetMMDeviceEnumeration()43 bool SetMMDeviceEnumeration() {
44 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get());
45 // Windows Wave is used as default if Windows XP was detected =>
46 // return false since MMDevice is not supported on XP.
47 if (amw->enumeration_type() == AudioManagerWin::kWaveEnumeration)
48 return false;
49
50 amw->SetEnumerationType(AudioManagerWin::kMMDeviceEnumeration);
51 return true;
52 }
53
SetWaveEnumeration()54 void SetWaveEnumeration() {
55 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get());
56 amw->SetEnumerationType(AudioManagerWin::kWaveEnumeration);
57 }
58
GetDeviceIdFromPCMWaveInAudioInputStream(const std::string & device_id)59 std::string GetDeviceIdFromPCMWaveInAudioInputStream(
60 const std::string& device_id) {
61 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get());
62 AudioParameters parameters(
63 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO,
64 AudioParameters::kAudioCDSampleRate, 16,
65 1024);
66 scoped_ptr<PCMWaveInAudioInputStream> stream(
67 static_cast<PCMWaveInAudioInputStream*>(
68 amw->CreatePCMWaveInAudioInputStream(parameters, device_id)));
69 return stream.get() ? stream->device_id_ : std::string();
70 }
71 #endif
72
73 // Helper method which verifies that the device list starts with a valid
74 // default record followed by non-default device names.
CheckDeviceNames(const AudioDeviceNames & device_names)75 static void CheckDeviceNames(const AudioDeviceNames& device_names) {
76 VLOG(2) << "Got " << device_names.size() << " audio devices.";
77 if (!device_names.empty()) {
78 AudioDeviceNames::const_iterator it = device_names.begin();
79
80 // The first device in the list should always be the default device.
81 EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceName),
82 it->device_name);
83 EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceId), it->unique_id);
84 ++it;
85
86 // Other devices should have non-empty name and id and should not contain
87 // default name or id.
88 while (it != device_names.end()) {
89 EXPECT_FALSE(it->device_name.empty());
90 EXPECT_FALSE(it->unique_id.empty());
91 VLOG(2) << "Device ID(" << it->unique_id
92 << "), label: " << it->device_name;
93 EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceName),
94 it->device_name);
95 EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceId),
96 it->unique_id);
97 ++it;
98 }
99 } else {
100 // Log a warning so we can see the status on the build bots. No need to
101 // break the test though since this does successfully test the code and
102 // some failure cases.
103 LOG(WARNING) << "No input devices detected";
104 }
105 }
106
CanRunInputTest()107 bool CanRunInputTest() {
108 return audio_manager_->HasAudioInputDevices();
109 }
110
CanRunOutputTest()111 bool CanRunOutputTest() {
112 return audio_manager_->HasAudioOutputDevices();
113 }
114
115 #if defined(USE_ALSA) || defined(USE_PULSEAUDIO)
116 template <class T>
CreateAudioManagerForTesting()117 void CreateAudioManagerForTesting() {
118 // Only one AudioManager may exist at a time, so destroy the one we're
119 // currently holding before creating a new one.
120 audio_manager_.reset();
121 audio_manager_.reset(T::Create(&fake_audio_log_factory_));
122 }
123 #endif
124
125 FakeAudioLogFactory fake_audio_log_factory_;
126 scoped_ptr<AudioManager> audio_manager_;
127
128 #if defined(OS_WIN)
129 // The MMDevice API requires COM to be initialized on the current thread.
130 base::win::ScopedCOMInitializer com_init_;
131 #endif
132 };
133
134 // Test that devices can be enumerated.
TEST_F(AudioManagerTest,EnumerateInputDevices)135 TEST_F(AudioManagerTest, EnumerateInputDevices) {
136 if (!CanRunInputTest())
137 return;
138
139 AudioDeviceNames device_names;
140 audio_manager_->GetAudioInputDeviceNames(&device_names);
141 CheckDeviceNames(device_names);
142 }
143
144 // Test that devices can be enumerated.
TEST_F(AudioManagerTest,EnumerateOutputDevices)145 TEST_F(AudioManagerTest, EnumerateOutputDevices) {
146 if (!CanRunOutputTest())
147 return;
148
149 AudioDeviceNames device_names;
150 audio_manager_->GetAudioOutputDeviceNames(&device_names);
151 CheckDeviceNames(device_names);
152 }
153
154 // Run additional tests for Windows since enumeration can be done using
155 // two different APIs. MMDevice is default for Vista and higher and Wave
156 // is default for XP and lower.
157 #if defined(OS_WIN)
158
159 // Override default enumeration API and force usage of Windows MMDevice.
160 // This test will only run on Windows Vista and higher.
TEST_F(AudioManagerTest,EnumerateInputDevicesWinMMDevice)161 TEST_F(AudioManagerTest, EnumerateInputDevicesWinMMDevice) {
162 if (!CanRunInputTest())
163 return;
164
165 AudioDeviceNames device_names;
166 if (!SetMMDeviceEnumeration()) {
167 // Usage of MMDevice will fail on XP and lower.
168 LOG(WARNING) << "MM device enumeration is not supported.";
169 return;
170 }
171 audio_manager_->GetAudioInputDeviceNames(&device_names);
172 CheckDeviceNames(device_names);
173 }
174
TEST_F(AudioManagerTest,EnumerateOutputDevicesWinMMDevice)175 TEST_F(AudioManagerTest, EnumerateOutputDevicesWinMMDevice) {
176 if (!CanRunOutputTest())
177 return;
178
179 AudioDeviceNames device_names;
180 if (!SetMMDeviceEnumeration()) {
181 // Usage of MMDevice will fail on XP and lower.
182 LOG(WARNING) << "MM device enumeration is not supported.";
183 return;
184 }
185 audio_manager_->GetAudioOutputDeviceNames(&device_names);
186 CheckDeviceNames(device_names);
187 }
188
189 // Override default enumeration API and force usage of Windows Wave.
190 // This test will run on Windows XP, Windows Vista and Windows 7.
TEST_F(AudioManagerTest,EnumerateInputDevicesWinWave)191 TEST_F(AudioManagerTest, EnumerateInputDevicesWinWave) {
192 if (!CanRunInputTest())
193 return;
194
195 AudioDeviceNames device_names;
196 SetWaveEnumeration();
197 audio_manager_->GetAudioInputDeviceNames(&device_names);
198 CheckDeviceNames(device_names);
199 }
200
TEST_F(AudioManagerTest,EnumerateOutputDevicesWinWave)201 TEST_F(AudioManagerTest, EnumerateOutputDevicesWinWave) {
202 if (!CanRunOutputTest())
203 return;
204
205 AudioDeviceNames device_names;
206 SetWaveEnumeration();
207 audio_manager_->GetAudioOutputDeviceNames(&device_names);
208 CheckDeviceNames(device_names);
209 }
210
TEST_F(AudioManagerTest,WinXPDeviceIdUnchanged)211 TEST_F(AudioManagerTest, WinXPDeviceIdUnchanged) {
212 if (!CanRunInputTest())
213 return;
214
215 AudioDeviceNames xp_device_names;
216 SetWaveEnumeration();
217 audio_manager_->GetAudioInputDeviceNames(&xp_device_names);
218 CheckDeviceNames(xp_device_names);
219
220 // Device ID should remain unchanged, including the default device ID.
221 for (AudioDeviceNames::iterator i = xp_device_names.begin();
222 i != xp_device_names.end(); ++i) {
223 EXPECT_EQ(i->unique_id,
224 GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id));
225 }
226 }
227
TEST_F(AudioManagerTest,ConvertToWinXPInputDeviceId)228 TEST_F(AudioManagerTest, ConvertToWinXPInputDeviceId) {
229 if (!CanRunInputTest())
230 return;
231
232 if (!SetMMDeviceEnumeration()) {
233 // Usage of MMDevice will fail on XP and lower.
234 LOG(WARNING) << "MM device enumeration is not supported.";
235 return;
236 }
237
238 AudioDeviceNames device_names;
239 audio_manager_->GetAudioInputDeviceNames(&device_names);
240 CheckDeviceNames(device_names);
241
242 for (AudioDeviceNames::iterator i = device_names.begin();
243 i != device_names.end(); ++i) {
244 std::string converted_id =
245 GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id);
246 if (i == device_names.begin()) {
247 // The first in the list is the default device ID, which should not be
248 // changed when passed to PCMWaveInAudioInputStream.
249 EXPECT_EQ(i->unique_id, converted_id);
250 } else {
251 // MMDevice-style device IDs should be converted to WaveIn-style device
252 // IDs.
253 EXPECT_NE(i->unique_id, converted_id);
254 }
255 }
256 }
257
258 #endif // defined(OS_WIN)
259
260 #if defined(USE_PULSEAUDIO)
261 // On Linux, there are two implementations available and both can
262 // sometimes be tested on a single system. These tests specifically
263 // test Pulseaudio.
264
TEST_F(AudioManagerTest,EnumerateInputDevicesPulseaudio)265 TEST_F(AudioManagerTest, EnumerateInputDevicesPulseaudio) {
266 if (!CanRunInputTest())
267 return;
268
269 CreateAudioManagerForTesting<AudioManagerPulse>();
270 if (audio_manager_.get()) {
271 AudioDeviceNames device_names;
272 audio_manager_->GetAudioInputDeviceNames(&device_names);
273 CheckDeviceNames(device_names);
274 } else {
275 LOG(WARNING) << "No pulseaudio on this system.";
276 }
277 }
278
TEST_F(AudioManagerTest,EnumerateOutputDevicesPulseaudio)279 TEST_F(AudioManagerTest, EnumerateOutputDevicesPulseaudio) {
280 if (!CanRunOutputTest())
281 return;
282
283 CreateAudioManagerForTesting<AudioManagerPulse>();
284 if (audio_manager_.get()) {
285 AudioDeviceNames device_names;
286 audio_manager_->GetAudioOutputDeviceNames(&device_names);
287 CheckDeviceNames(device_names);
288 } else {
289 LOG(WARNING) << "No pulseaudio on this system.";
290 }
291 }
292 #endif // defined(USE_PULSEAUDIO)
293
294 #if defined(USE_ALSA)
295 // On Linux, there are two implementations available and both can
296 // sometimes be tested on a single system. These tests specifically
297 // test Alsa.
298
TEST_F(AudioManagerTest,EnumerateInputDevicesAlsa)299 TEST_F(AudioManagerTest, EnumerateInputDevicesAlsa) {
300 if (!CanRunInputTest())
301 return;
302
303 VLOG(2) << "Testing AudioManagerAlsa.";
304 CreateAudioManagerForTesting<AudioManagerAlsa>();
305 AudioDeviceNames device_names;
306 audio_manager_->GetAudioInputDeviceNames(&device_names);
307 CheckDeviceNames(device_names);
308 }
309
TEST_F(AudioManagerTest,EnumerateOutputDevicesAlsa)310 TEST_F(AudioManagerTest, EnumerateOutputDevicesAlsa) {
311 if (!CanRunOutputTest())
312 return;
313
314 VLOG(2) << "Testing AudioManagerAlsa.";
315 CreateAudioManagerForTesting<AudioManagerAlsa>();
316 AudioDeviceNames device_names;
317 audio_manager_->GetAudioOutputDeviceNames(&device_names);
318 CheckDeviceNames(device_names);
319 }
320 #endif // defined(USE_ALSA)
321
TEST_F(AudioManagerTest,GetDefaultOutputStreamParameters)322 TEST_F(AudioManagerTest, GetDefaultOutputStreamParameters) {
323 #if defined(OS_WIN) || defined(OS_MACOSX)
324 if (!CanRunInputTest())
325 return;
326
327 AudioParameters params = audio_manager_->GetDefaultOutputStreamParameters();
328 EXPECT_TRUE(params.IsValid());
329 #endif // defined(OS_WIN) || defined(OS_MACOSX)
330 }
331
TEST_F(AudioManagerTest,GetAssociatedOutputDeviceID)332 TEST_F(AudioManagerTest, GetAssociatedOutputDeviceID) {
333 #if defined(OS_WIN) || defined(OS_MACOSX)
334 if (!CanRunInputTest() || !CanRunOutputTest())
335 return;
336
337 AudioDeviceNames device_names;
338 audio_manager_->GetAudioInputDeviceNames(&device_names);
339 bool found_an_associated_device = false;
340 for (AudioDeviceNames::iterator it = device_names.begin();
341 it != device_names.end();
342 ++it) {
343 EXPECT_FALSE(it->unique_id.empty());
344 EXPECT_FALSE(it->device_name.empty());
345 std::string output_device_id(
346 audio_manager_->GetAssociatedOutputDeviceID(it->unique_id));
347 if (!output_device_id.empty()) {
348 VLOG(2) << it->unique_id << " matches with " << output_device_id;
349 found_an_associated_device = true;
350 }
351 }
352
353 EXPECT_TRUE(found_an_associated_device);
354 #endif // defined(OS_WIN) || defined(OS_MACOSX)
355 }
356
357 } // namespace media
358