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