Home | History | Annotate | Download | only in audio
      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