• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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