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