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