summaryrefslogtreecommitdiffstats
path: root/media/audio
diff options
context:
space:
mode:
authoryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 23:16:45 +0000
committeryzshen@chromium.org <yzshen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-14 23:16:45 +0000
commit6bf4b60d0cd6d28951eeb8fe65f78345fa42a340 (patch)
tree06b6aff4ed3a667911524829a8dca4f143286428 /media/audio
parentec13c99dec55964f7f06bba49d2ff5cdb55f9c50 (diff)
downloadchromium_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.cc58
-rw-r--r--media/audio/win/audio_manager_win.cc28
-rw-r--r--media/audio/win/audio_manager_win.h9
-rw-r--r--media/audio/win/device_enumeration_win.cc58
-rw-r--r--media/audio/win/device_enumeration_win.h16
-rw-r--r--media/audio/win/wavein_input_win.cc2
-rw-r--r--media/audio/win/wavein_input_win.h3
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,