diff options
author | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-14 23:16:45 +0000 |
---|---|---|
committer | yzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-14 23:16:45 +0000 |
commit | 6bf4b60d0cd6d28951eeb8fe65f78345fa42a340 (patch) | |
tree | 06b6aff4ed3a667911524829a8dca4f143286428 /media/audio | |
parent | ec13c99dec55964f7f06bba49d2ff5cdb55f9c50 (diff) | |
download | chromium_src-6bf4b60d0cd6d28951eeb8fe65f78345fa42a340.zip chromium_src-6bf4b60d0cd6d28951eeb8fe65f78345fa42a340.tar.gz chromium_src-6bf4b60d0cd6d28951eeb8fe65f78345fa42a340.tar.bz2 |
On windows, create PCMWaveInAudioInputStream instance with correct device ID.
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/9566002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@126779 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/audio')
-rw-r--r-- | media/audio/audio_input_device_unittest.cc | 58 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.cc | 28 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.h | 9 | ||||
-rw-r--r-- | media/audio/win/device_enumeration_win.cc | 58 | ||||
-rw-r--r-- | media/audio/win/device_enumeration_win.h | 16 | ||||
-rw-r--r-- | media/audio/win/wavein_input_win.cc | 2 | ||||
-rw-r--r-- | media/audio/win/wavein_input_win.h | 3 |
7 files changed, 164 insertions, 10 deletions
diff --git a/media/audio/audio_input_device_unittest.cc b/media/audio/audio_input_device_unittest.cc index 0917b79..470dbab 100644 --- a/media/audio/audio_input_device_unittest.cc +++ b/media/audio/audio_input_device_unittest.cc @@ -7,10 +7,12 @@ #include "base/win/scoped_com_initializer.h" #include "media/audio/audio_manager.h" #include "media/audio/audio_manager_base.h" +#include "testing/gtest/include/gtest/gtest.h" + #if defined(OS_WIN) #include "media/audio/win/audio_manager_win.h" +#include "media/audio/win/wavein_input_win.h" #endif -#include "testing/gtest/include/gtest/gtest.h" using base::win::ScopedCOMInitializer; using media::AudioDeviceNames; @@ -41,6 +43,19 @@ class AudioInputDeviceTest AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); amw->SetEnumerationType(AudioManagerWin::kWaveEnumeration); } + + std::string GetDeviceIdFromPCMWaveInAudioInputStream( + const std::string& device_id) { + AudioManagerWin* amw = static_cast<AudioManagerWin*>(audio_manager_.get()); + AudioParameters parameters( + AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, + AudioParameters::kAudioCDSampleRate, 16, + 1024); + scoped_ptr<PCMWaveInAudioInputStream> stream( + static_cast<PCMWaveInAudioInputStream*>( + amw->CreatePCMWaveInAudioInputStream(parameters, device_id))); + return stream.get() ? stream->device_id_ : std::string(); + } #endif // Helper method which verifies that the device list starts with a valid @@ -114,4 +129,45 @@ TEST_F(AudioInputDeviceTest, EnumerateDevicesWinWave) { CheckDeviceNames(device_names); } +TEST_F(AudioInputDeviceTest, WinXPDeviceIdUnchanged) { + AudioDeviceNames xp_device_names; + SetWaveEnumeration(); + audio_manager_->GetAudioInputDeviceNames(&xp_device_names); + CheckDeviceNames(xp_device_names); + + // Device ID should remain unchanged, including the default device ID. + for (AudioDeviceNames::iterator i = xp_device_names.begin(); + i != xp_device_names.end(); ++i) { + EXPECT_EQ(i->unique_id, + GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id)); + } +} + +TEST_F(AudioInputDeviceTest, ConvertToWinXPDeviceId) { + if (!SetMMDeviceEnumeration()) { + // Usage of MMDevice will fail on XP and lower. + LOG(WARNING) << "MM device enumeration is not supported."; + return; + } + + AudioDeviceNames device_names; + audio_manager_->GetAudioInputDeviceNames(&device_names); + CheckDeviceNames(device_names); + + for (AudioDeviceNames::iterator i = device_names.begin(); + i != device_names.end(); ++i) { + std::string converted_id = + GetDeviceIdFromPCMWaveInAudioInputStream(i->unique_id); + if (i == device_names.begin()) { + // The first in the list is the default device ID, which should not be + // changed when passed to PCMWaveInAudioInputStream. + EXPECT_EQ(i->unique_id, converted_id); + } else { + // MMDevice-style device IDs should be converted to WaveIn-style device + // IDs. + EXPECT_NE(i->unique_id, converted_id); + } + } +} + #endif diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc index 66f4a55..7aebfe0 100644 --- a/media/audio/win/audio_manager_win.cc +++ b/media/audio/win/audio_manager_win.cc @@ -218,10 +218,10 @@ void AudioManagerWin::GetAudioInputDeviceNames( // Enumerate all active audio-endpoint capture devices. if (enumeration_type() == kWaveEnumeration) { // Utilize the Wave API for Windows XP. - GetInputDeviceNamesWinXP(device_names); + media::GetInputDeviceNamesWinXP(device_names); } else { // Utilize the MMDevice API (part of Core Audio) for Vista and higher. - GetInputDeviceNamesWin(device_names); + media::GetInputDeviceNamesWin(device_names); } // Always add default device parameters as first element. @@ -275,8 +275,7 @@ AudioOutputStream* AudioManagerWin::MakeLowLatencyOutputStream( AudioInputStream* AudioManagerWin::MakeLinearInputStream( const AudioParameters& params, const std::string& device_id) { DCHECK_EQ(AudioParameters::AUDIO_PCM_LINEAR, params.format); - return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, - AudioManagerBase::kDefaultDeviceId); + return CreatePCMWaveInAudioInputStream(params, device_id); } // Factory for the implementations of AudioInputStream for @@ -288,8 +287,7 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( if (!media::IsWASAPISupported()) { // Fall back to Windows Wave implementation on Windows XP or lower. DVLOG(1) << "Using WaveIn since WASAPI requires at least Vista."; - stream = new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, - device_id); + stream = CreatePCMWaveInAudioInputStream(params, device_id); } else { stream = new WASAPIAudioInputStream(this, params, device_id); } @@ -297,6 +295,24 @@ AudioInputStream* AudioManagerWin::MakeLowLatencyInputStream( return stream; } +AudioInputStream* AudioManagerWin::CreatePCMWaveInAudioInputStream( + const AudioParameters& params, + const std::string& device_id) { + std::string xp_device_id = device_id; + if (device_id != AudioManagerBase::kDefaultDeviceId && + enumeration_type_ == kMMDeviceEnumeration) { + xp_device_id = media::ConvertToWinXPDeviceId(device_id); + if (xp_device_id.empty()) { + DLOG(ERROR) << "Cannot find a waveIn device which matches the device ID " + << device_id; + return NULL; + } + } + + return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers, + xp_device_id); +} + /// static AudioManager* CreateAudioManager() { return new AudioManagerWin(); diff --git a/media/audio/win/audio_manager_win.h b/media/audio/win/audio_manager_win.h index 3539ef0..19742fb 100644 --- a/media/audio/win/audio_manager_win.h +++ b/media/audio/win/audio_manager_win.h @@ -59,6 +59,15 @@ class MEDIA_EXPORT AudioManagerWin : public AudioManagerBase { enumeration_type_ = type; } + // Returns a PCMWaveInAudioInputStream instance or NULL on failure. + // This method converts MMDevice-style device ID to WaveIn-style device ID if + // necessary. + // (Please see device_enumeration_win.h for more info about the two kinds of + // device IDs.) + AudioInputStream* CreatePCMWaveInAudioInputStream( + const AudioParameters& params, + const std::string& device_id); + DISALLOW_COPY_AND_ASSIGN(AudioManagerWin); }; diff --git a/media/audio/win/device_enumeration_win.cc b/media/audio/win/device_enumeration_win.cc index 0087a89..ddd8094 100644 --- a/media/audio/win/device_enumeration_win.cc +++ b/media/audio/win/device_enumeration_win.cc @@ -1,4 +1,4 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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. @@ -17,6 +17,13 @@ using media::AudioDeviceNames; using base::win::ScopedComPtr; using base::win::ScopedCoMem; +// Taken from Mmddk.h. +#define DRV_RESERVED 0x0800 +#define DRV_QUERYFUNCTIONINSTANCEID (DRV_RESERVED + 17) +#define DRV_QUERYFUNCTIONINSTANCEIDSIZE (DRV_RESERVED + 18) + +namespace media { + 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. @@ -123,3 +130,52 @@ bool GetInputDeviceNamesWinXP(AudioDeviceNames* device_names) { return true; } + +std::string ConvertToWinXPDeviceId(const std::string& device_id) { + UINT number_of_active_devices = waveInGetNumDevs(); + MMRESULT result = MMSYSERR_NOERROR; + + UINT i = 0; + for (; i < number_of_active_devices; ++i) { + size_t size = 0; + // Get the size (including the terminating NULL) of the endpoint ID of the + // waveIn device. + result = waveInMessage(reinterpret_cast<HWAVEIN>(i), + DRV_QUERYFUNCTIONINSTANCEIDSIZE, + reinterpret_cast<DWORD_PTR>(&size), NULL); + if (result != MMSYSERR_NOERROR) + continue; + + ScopedCoMem<WCHAR> id; + id.Reset(static_cast<WCHAR*>(CoTaskMemAlloc(size))); + if (!id) + continue; + + // Get the endpoint ID string for this waveIn device. + result = waveInMessage( + reinterpret_cast<HWAVEIN>(i), DRV_QUERYFUNCTIONINSTANCEID, + reinterpret_cast<DWORD_PTR>(static_cast<WCHAR*>(id)), size); + if (result != MMSYSERR_NOERROR) + continue; + + std::string utf8_id = WideToUTF8(static_cast<WCHAR*>(id)); + // Check whether the endpoint ID string of this waveIn device matches that + // of the audio endpoint device. + if (device_id == utf8_id) + break; + } + + // If a matching waveIn device was found, convert the unique endpoint ID + // string to a standard friendly name with max 32 characters. + if (i < number_of_active_devices) { + WAVEINCAPS capabilities; + + result = waveInGetDevCaps(i, &capabilities, sizeof(capabilities)); + if (result == MMSYSERR_NOERROR) + return WideToUTF8(capabilities.szPname); + } + + return std::string(); +} + +} // namespace media diff --git a/media/audio/win/device_enumeration_win.h b/media/audio/win/device_enumeration_win.h index a797eec..3d44670 100644 --- a/media/audio/win/device_enumeration_win.h +++ b/media/audio/win/device_enumeration_win.h @@ -1,12 +1,16 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Copyright (c) 2012 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 <string> + #include "media/audio/audio_device_name.h" +namespace media { + // 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: @@ -22,5 +26,15 @@ bool GetInputDeviceNamesWin(media::AudioDeviceNames* device_names); // - unique_id: "Microphone (Realtek High Defini" (same as friendly name). bool GetInputDeviceNamesWinXP(media::AudioDeviceNames* device_names); +// Converts a device ID generated by |GetInputDeviceNamesWin()| to the +// corresponding ID by |GetInputDeviceNamesWinXP()|. Returns an empty string on +// failure. +// Example input and output: +// - input ID: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}" +// - output ID: "Microphone (Realtek High Defini" +std::string ConvertToWinXPDeviceId(const std::string& device_id); + +} // namespace media + #endif // MEDIA_AUDIO_WIN_DEVICE_ENUMERATION_WIN_H_ diff --git a/media/audio/win/wavein_input_win.cc b/media/audio/win/wavein_input_win.cc index 10f0df0..cd9febc 100644 --- a/media/audio/win/wavein_input_win.cc +++ b/media/audio/win/wavein_input_win.cc @@ -222,7 +222,7 @@ bool PCMWaveInAudioInputStream::GetDeviceId(UINT* device_index) { // Get list of all available and active devices. AudioDeviceNames device_names; - if (!GetInputDeviceNamesWinXP(&device_names)) + if (!media::GetInputDeviceNamesWinXP(&device_names)) return false; if (device_names.empty()) diff --git a/media/audio/win/wavein_input_win.h b/media/audio/win/wavein_input_win.h index 66465a8..a9b4b91 100644 --- a/media/audio/win/wavein_input_win.h +++ b/media/audio/win/wavein_input_win.h @@ -47,6 +47,9 @@ class PCMWaveInAudioInputStream : public AudioInputStream { kStateClosed // Device has been released. }; + // Allow unit tests to query the device ID. + friend class AudioInputDeviceTest; + // Windows calls us back with the recorded audio data here. See msdn // documentation for 'waveInProc' for details about the parameters. static void CALLBACK WaveCallback(HWAVEIN hwi, UINT msg, DWORD_PTR instance, |