diff options
author | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 07:18:19 +0000 |
---|---|---|
committer | henrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-24 07:18:19 +0000 |
commit | d5577f7266e34ed412fd3b9b9aed2450094b5995 (patch) | |
tree | 806c82daafc17fc3700ea9800217dbbbf4fa9ea3 /media/audio/win | |
parent | a3c8aa0b48eefddfe8718febb58bd7a685339e08 (diff) | |
download | chromium_src-d5577f7266e34ed412fd3b9b9aed2450094b5995.zip chromium_src-d5577f7266e34ed412fd3b9b9aed2450094b5995.tar.gz chromium_src-d5577f7266e34ed412fd3b9b9aed2450094b5995.tar.bz2 |
Adds support for capture device enumeration on Windows.
Example output (two devices found on Windows 7 machine):
device_name: Microphone (6- SB Arena Headset)
unique_id: {0.0.1.00000000}.{24515814-26fd-4382-b4bc-0a8d847ed853}
device_name: Microphone (Realtek High Definition Audio)
unique_id: {0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}
BUG=None
TEST=audio_input_device_unittest.cc
Review URL: http://codereview.chromium.org/8606006
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@111500 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio/win')
-rw-r--r-- | media/audio/win/audio_manager_win.cc | 29 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.h | 19 | ||||
-rw-r--r-- | media/audio/win/device_enumeration_win.cc | 125 | ||||
-rw-r--r-- | media/audio/win/device_enumeration_win.h | 26 |
4 files changed, 191 insertions, 8 deletions
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index c999f61..92f59d8 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -24,6 +24,7 @@ #include "media/audio/win/audio_low_latency_input_win.h" #include "media/audio/win/audio_low_latency_output_win.h" #include "media/audio/win/audio_manager_win.h" +#include "media/audio/win/device_enumeration_win.h" #include "media/audio/win/wavein_input_win.h" #include "media/audio/win/waveout_output_win.h" #include "media/base/limits.h" @@ -99,6 +100,13 @@ static string16 GetDeviceAndDriverInfo(HDEVINFO device_info, AudioManagerWin::AudioManagerWin() : num_output_streams_(0) { + if (base::win::GetVersion() <= base::win::VERSION_XP) { + // Use the Wave API for device enumeration if XP or lower. + enumeration_type_ = kWaveEnumeration; + } else { + // Use the MMDevice API for device enumeration if Vista or higher. + enumeration_type_ = kMMDeviceEnumeration; + } } AudioManagerWin::~AudioManagerWin() { @@ -280,19 +288,26 @@ void AudioManagerWin::ShowAudioInputSettings() { void AudioManagerWin::GetAudioInputDeviceNames( media::AudioDeviceNames* device_names) { - // TODO(xians): query a full list of valid devices. - if (HasAudioInputDevices()) { - // Add the default device to the list. - // We use index 0 to make up the unique_id to identify the - // default devices. + DCHECK(enumeration_type() != kUninitializedEnumeration); + // Enumerate all active audio-endpoint capture devices. + if (enumeration_type() == kWaveEnumeration) { + // Utilize the Wave API for Windows XP. + GetInputDeviceNamesWinXP(device_names); + } else { + // Utilize the MMDevice API (part of Core Audio) for Vista and higher. + GetInputDeviceNamesWin(device_names); + } + + // Always add default device parameters as first element. + if (!device_names->empty()) { media::AudioDeviceName name; name.device_name = AudioManagerBase::kDefaultDeviceName; name.unique_id = AudioManagerBase::kDefaultDeviceId; - device_names->push_back(name); + device_names->push_front(name); } } -// static +/// static AudioManager* AudioManager::CreateAudioManager() { return new AudioManagerWin(); } diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index f1d73d8..6c519ee 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -6,9 +6,11 @@ #define MEDIA_AUDIO_WIN_AUDIO_MANAGER_WIN_H_ #include <windows.h> +#include <string> #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" #include "media/audio/audio_manager_base.h" class PCMWaveOutAudioOutputStream; @@ -16,7 +18,7 @@ class PCMWaveOutAudioOutputStream; // Windows implementation of the AudioManager singleton. This class is internal // to the audio output and only internal users can call methods not exposed by // the AudioManager class. -class AudioManagerWin : public AudioManagerBase { +class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { public: AudioManagerWin(); // Implementation of AudioManager. @@ -42,8 +44,23 @@ class AudioManagerWin : public AudioManagerBase { void ReleaseInputStream(AudioInputStream* stream); private: + enum EnumerationType { + kUninitializedEnumeration = 0, + kMMDeviceEnumeration, + kWaveEnumeration, + }; + virtual ~AudioManagerWin(); + // Allow unit test to modify the utilized enumeration API. + friend class AudioInputDeviceTest; + + EnumerationType enumeration_type_; + EnumerationType enumeration_type() { return enumeration_type_; } + void SetEnumerationType(EnumerationType type) { + enumeration_type_ = type; + } + // Number of currently open output streams. int num_output_streams_; diff --git a/media/audio/win/device_enumeration_win.cc b/media/audio/win/device_enumeration_win.cc new file mode 100644 index 0000000..0087a89 --- /dev/null +++ b/media/audio/win/device_enumeration_win.cc @@ -0,0 +1,125 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <MMDeviceAPI.h> +#include <mmsystem.h> +#include <Functiondiscoverykeys_devpkey.h> // MMDeviceAPI.h must come first + +#include "media/audio/win/audio_manager_win.h" + +#include "base/logging.h" +#include "base/utf_string_conversions.h" +#include "base/win/scoped_co_mem.h" +#include "base/win/scoped_comptr.h" + +using media::AudioDeviceNames; +using base::win::ScopedComPtr; +using base::win::ScopedCoMem; + +bool GetInputDeviceNamesWin(AudioDeviceNames* device_names) { + // It is assumed that this method is called from a COM thread, i.e., + // CoInitializeEx() is not called here again to avoid STA/MTA conflicts. + ScopedComPtr<IMMDeviceEnumerator> enumerator; + HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IMMDeviceEnumerator), + enumerator.ReceiveVoid()); + if (FAILED(hr)) { + LOG(WARNING) << "Failed to create IMMDeviceEnumerator: " << std::hex << hr; + return false; + } + + // Generate a collection of active audio capture endpoint devices. + // This method will succeed even if all devices are disabled. + ScopedComPtr<IMMDeviceCollection> collection; + hr = enumerator->EnumAudioEndpoints(eCapture, + DEVICE_STATE_ACTIVE, + collection.Receive()); + if (FAILED(hr)) + return false; + + // Retrieve the number of active capture devices. + UINT number_of_active_devices = 0; + collection->GetCount(&number_of_active_devices); + if (number_of_active_devices == 0) + return true; + + media::AudioDeviceName device; + + // Loop over all active capture devices and add friendly name and + // unique ID to the |device_names| list. + for (UINT i = 0; i < number_of_active_devices; ++i) { + // Retrieve unique name of endpoint device. + // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}". + ScopedComPtr<IMMDevice> audio_device; + ScopedCoMem<WCHAR> endpoint_device_id; + hr = collection->Item(i, audio_device.Receive()); + if (FAILED(hr)) + continue; + audio_device->GetId(&endpoint_device_id); + + // Store the unique name. + device.unique_id = WideToUTF8(static_cast<WCHAR*>(endpoint_device_id)); + + // Retrieve user-friendly name of endpoint device. + // Example: "Microphone (Realtek High Definition Audio)". + ScopedComPtr<IPropertyStore> properties; + hr = audio_device->OpenPropertyStore(STGM_READ, properties.Receive()); + if (SUCCEEDED(hr)) { + PROPVARIANT friendly_name; + PropVariantInit(&friendly_name); + hr = properties->GetValue(PKEY_Device_FriendlyName, &friendly_name); + + // Store the user-friendly name. + if (SUCCEEDED(hr) && + friendly_name.vt == VT_LPWSTR && friendly_name.pwszVal) { + device.device_name = WideToUTF8(friendly_name.pwszVal); + } + PropVariantClear(&friendly_name); + } + + // Add combination of user-friendly and unique name to the output list. + device_names->push_back(device); + } + + return true; +} + +bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) { + // Retrieve the number of active waveform input devices. + UINT number_of_active_devices = waveInGetNumDevs(); + if (number_of_active_devices == 0) + return true; + + media::AudioDeviceName device; + WAVEINCAPS capabilities; + MMRESULT err = MMSYSERR_NOERROR; + + // Loop over all active capture devices and add friendly name and + // unique ID to the |device_names| list. Note that, for Wave on XP, + // the "unique" name will simply be a copy of the friendly name since + // there is no safe method to retrieve a unique device name on XP. + for (UINT i = 0; i < number_of_active_devices; ++i) { + // Retrieve the capabilities of the specified waveform-audio input device. + err = waveInGetDevCaps(i, &capabilities, sizeof(capabilities)); + if (err != MMSYSERR_NOERROR) + continue; + + if (capabilities.szPname != NULL) { + // Store the user-friendly name. Max length is MAXPNAMELEN(=32) + // characters and the name cane be truncated on XP. + // Example: "Microphone (Realtek High Defini". + device.device_name = WideToUTF8(capabilities.szPname); + + // Store the "unique" name (we use same as friendly name on Windows XP). + device.unique_id = WideToUTF8(capabilities.szPname); + + // Add combination of user-friendly and unique name to the output list. + device_names->push_back(device); + } + } + + return true; +} diff --git a/media/audio/win/device_enumeration_win.h b/media/audio/win/device_enumeration_win.h new file mode 100644 index 0000000..a797eec --- /dev/null +++ b/media/audio/win/device_enumeration_win.h @@ -0,0 +1,26 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_AUDIO_WIN_DEVICE_ENUMERATION_WIN_H_ +#define MEDIA_AUDIO_WIN_DEVICE_ENUMERATION_WIN_H_ + +#include "media/audio/audio_device_name.h" + +// Returns a list of audio input device structures (name and unique device ID) +// using the MMDevice API which is supported on Windows Vista and higher. +// Example record in the output list: +// - device_name: "Microphone (Realtek High Definition Audio)". +// - unique_id: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}" +// This method must be called from a COM thread using MTA. +bool GetInputDeviceNamesWin(media::AudioDeviceNames* device_names); + +// Returns a list of audio input device structures (name and unique device ID) +// using the WaveIn API which is supported on Windows XP and higher. +// Example record in the output list: +// - device_name: "Microphone (Realtek High Defini". +// - unique_id: "Microphone (Realtek High Defini" (same as friendly name). +bool GetInputDeviceNamesWinXP(media::AudioDeviceNames* device_names); + +#endif // MEDIA_AUDIO_WIN_DEVICE_ENUMERATION_WIN_H_ + |