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/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_WIN) 13 #include "base/win/scoped_com_initializer.h" 14 #include "media/audio/win/audio_manager_win.h" 15 #include "media/audio/win/wavein_input_win.h" 16 #endif 17 18 namespace media { 19 20 // Test fixture which allows us to override the default enumeration API on 21 // Windows. 22 class AudioInputDeviceTest 23 : public ::testing::Test { 24 protected: 25 AudioInputDeviceTest() 26 : audio_manager_(AudioManager::Create()) 27 #if defined(OS_WIN) 28 , com_init_(base::win::ScopedCOMInitializer::kMTA) 29 #endif 30 { 31 } 32 33 #if defined(OS_WIN) 34 bool SetMMDeviceEnumeration() { 35 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); 36 // Windows Wave is used as default if Windows XP was detected => 37 // return false since MMDevice is not supported on XP. 38 if (amw->enumeration_type() == AudioManagerWin::kWaveEnumeration) 39 return false; 40 41 amw->SetEnumerationType(AudioManagerWin::kMMDeviceEnumeration); 42 return true; 43 } 44 45 void SetWaveEnumeration() { 46 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); 47 amw->SetEnumerationType(AudioManagerWin::kWaveEnumeration); 48 } 49 50 std::string GetDeviceIdFromPCMWaveInAudioInputStream( 51 const std::string& device_id) { 52 AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); 53 AudioParameters parameters( 54 AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 55 AudioParameters::kAudioCDSampleRate, 16, 56 1024); 57 scoped_ptr<PCMWaveInAudioInputStream> stream( 58 static_cast<PCMWaveInAudioInputStream*>( 59 amw->CreatePCMWaveInAudioInputStream(parameters, device_id))); 60 return stream.get() ? stream->device_id_ : std::string(); 61 } 62 #endif 63 64 // Helper method which verifies that the device list starts with a valid 65 // default record followed by non-default device names. 66 static void CheckDeviceNames(const AudioDeviceNames& device_names) { 67 if (!device_names.empty()) { 68 AudioDeviceNames::const_iterator it = device_names.begin(); 69 70 // The first device in the list should always be the default device. 71 EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceName), 72 it->device_name); 73 EXPECT_EQ(std::string(AudioManagerBase::kDefaultDeviceId), it->unique_id); 74 ++it; 75 76 // Other devices should have non-empty name and id and should not contain 77 // default name or id. 78 while (it != device_names.end()) { 79 EXPECT_FALSE(it->device_name.empty()); 80 EXPECT_FALSE(it->unique_id.empty()); 81 EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceName), 82 it->device_name); 83 EXPECT_NE(std::string(AudioManagerBase::kDefaultDeviceId), 84 it->unique_id); 85 ++it; 86 } 87 } else { 88 // Log a warning so we can see the status on the build bots. No need to 89 // break the test though since this does successfully test the code and 90 // some failure cases. 91 LOG(WARNING) << "No input devices detected"; 92 } 93 } 94 95 bool CanRunAudioTest() { 96 return audio_manager_->HasAudioInputDevices(); 97 } 98 99 scoped_ptr<AudioManager> audio_manager_; 100 101 #if defined(OS_WIN) 102 // The MMDevice API requires COM to be initialized on the current thread. 103 base::win::ScopedCOMInitializer com_init_; 104 #endif 105 }; 106 107 // Test that devices can be enumerated. 108 TEST_F(AudioInputDeviceTest, EnumerateDevices) { 109 if (!CanRunAudioTest()) 110 return; 111 112 AudioDeviceNames device_names; 113 audio_manager_->GetAudioInputDeviceNames(&device_names); 114 CheckDeviceNames(device_names); 115 } 116 117 // Run additional tests for Windows since enumeration can be done using 118 // two different APIs. MMDevice is default for Vista and higher and Wave 119 // is default for XP and lower. 120 #if defined(OS_WIN) 121 122 // Override default enumeration API and force usage of Windows MMDevice. 123 // This test will only run on Windows Vista and higher. 124 TEST_F(AudioInputDeviceTest, EnumerateDevicesWinMMDevice) { 125 if (!CanRunAudioTest()) 126 return; 127 128 AudioDeviceNames device_names; 129 if (!SetMMDeviceEnumeration()) { 130 // Usage of MMDevice will fail on XP and lower. 131 LOG(WARNING) << "MM device enumeration is not supported."; 132 return; 133 } 134 audio_manager_->GetAudioInputDeviceNames(&device_names); 135 CheckDeviceNames(device_names); 136 } 137 138 // Override default enumeration API and force usage of Windows Wave. 139 // This test will run on Windows XP, Windows Vista and Windows 7. 140 TEST_F(AudioInputDeviceTest, EnumerateDevicesWinWave) { 141 if (!CanRunAudioTest()) 142 return; 143 144 AudioDeviceNames device_names; 145 SetWaveEnumeration(); 146 audio_manager_->GetAudioInputDeviceNames(&device_names); 147 CheckDeviceNames(device_names); 148 } 149 150 TEST_F(AudioInputDeviceTest, WinXPDeviceIdUnchanged) { 151 if (!CanRunAudioTest()) 152 return; 153 154 AudioDeviceNames xp_device_names; 155 SetWaveEnumeration(); 156 audio_manager_->GetAudioInputDeviceNames(&xp_device_names); 157 CheckDeviceNames(xp_device_names); 158 159 // Device ID should remain unchanged, including the default device ID. 160 for (AudioDeviceNames::iterator i = xp_device_names.begin(); 161 i != xp_device_names.end(); ++i) { 162 EXPECT_EQ(i->unique_id, 163 GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id)); 164 } 165 } 166 167 TEST_F(AudioInputDeviceTest, ConvertToWinXPDeviceId) { 168 if (!CanRunAudioTest()) 169 return; 170 171 if (!SetMMDeviceEnumeration()) { 172 // Usage of MMDevice will fail on XP and lower. 173 LOG(WARNING) << "MM device enumeration is not supported."; 174 return; 175 } 176 177 AudioDeviceNames device_names; 178 audio_manager_->GetAudioInputDeviceNames(&device_names); 179 CheckDeviceNames(device_names); 180 181 for (AudioDeviceNames::iterator i = device_names.begin(); 182 i != device_names.end(); ++i) { 183 std::string converted_id = 184 GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id); 185 if (i == device_names.begin()) { 186 // The first in the list is the default device ID, which should not be 187 // changed when passed to PCMWaveInAudioInputStream. 188 EXPECT_EQ(i->unique_id, converted_id); 189 } else { 190 // MMDevice-style device IDs should be converted to WaveIn-style device 191 // IDs. 192 EXPECT_NE(i->unique_id, converted_id); 193 } 194 } 195 } 196 197 #endif 198 199 } // namespace media 200