summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-06 09:53:14 +0000
committerhenrika@chromium.org <henrika@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-12-06 09:53:14 +0000
commitcb28f1388a75bef2a93878f242f38429aba9d2f5 (patch)
tree23829380c5dd97bf514468a467c112f451fb95ac /media
parentef5e98e345ffb8baeb16cd2a42d5790ac46df82f (diff)
downloadchromium_src-cb28f1388a75bef2a93878f242f38429aba9d2f5.zip
chromium_src-cb28f1388a75bef2a93878f242f38429aba9d2f5.tar.gz
chromium_src-cb28f1388a75bef2a93878f242f38429aba9d2f5.tar.bz2
Adds input device selection on Windows.
This CL does not change anything for any other audio client but the WebRTC clients. All other clients can ignore this new functionality and will still use the default input device as before. BUG=none TEST=special version of content_unittests --gtest_filter=WebRTCAudioDeviceTest* Review URL: http://codereview.chromium.org/8770005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@113173 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/audio/win/audio_low_latency_input_win.cc43
-rw-r--r--media/audio/win/audio_low_latency_input_win.h10
-rw-r--r--media/audio/win/audio_manager_win.cc14
-rw-r--r--media/audio/win/wavein_input_win.cc58
-rw-r--r--media/audio/win/wavein_input_win.h13
5 files changed, 101 insertions, 37 deletions
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc
index dd83f7e..fc6630b 100644
--- a/media/audio/win/audio_low_latency_input_win.cc
+++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -15,14 +15,15 @@ using base::win::ScopedComPtr;
using base::win::ScopedCOMInitializer;
WASAPIAudioInputStream::WASAPIAudioInputStream(
- AudioManagerWin* manager, const AudioParameters& params, ERole device_role)
+ AudioManagerWin* manager, const AudioParameters& params,
+ const std::string& device_id)
: com_init_(ScopedCOMInitializer::kMTA),
manager_(manager),
capture_thread_(NULL),
opened_(false),
started_(false),
endpoint_buffer_size_frames_(0),
- device_role_(device_role),
+ device_id_(device_id),
sink_(NULL) {
DCHECK(manager_);
@@ -78,9 +79,10 @@ bool WASAPIAudioInputStream::Open() {
if (opened_)
return false;
- // Obtain a reference to the IMMDevice interface of the default capturing
- // device with the specified role.
- HRESULT hr = SetCaptureDevice(device_role_);
+ // Obtain a reference to the IMMDevice interface of the capturing
+ // device with the specified unique identifier or role which was
+ // set at construction.
+ HRESULT hr = SetCaptureDevice();
if (FAILED(hr)) {
return false;
}
@@ -379,7 +381,7 @@ void WASAPIAudioInputStream::HandleError(HRESULT err) {
sink_->OnError(this, static_cast<int>(err));
}
-HRESULT WASAPIAudioInputStream::SetCaptureDevice(ERole device_role) {
+HRESULT WASAPIAudioInputStream::SetCaptureDevice() {
ScopedComPtr<IMMDeviceEnumerator> enumerator;
HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
NULL,
@@ -387,14 +389,27 @@ HRESULT WASAPIAudioInputStream::SetCaptureDevice(ERole device_role) {
__uuidof(IMMDeviceEnumerator),
enumerator.ReceiveVoid());
if (SUCCEEDED(hr)) {
- // Retrieve the default capture audio endpoint for the specified role.
- // Note that, in Windows Vista, the MMDevice API supports device roles
- // but the system-supplied user interface programs do not.
- hr = enumerator->GetDefaultAudioEndpoint(eCapture,
- device_role,
- endpoint_device_.Receive());
-
- // Verify that the audio endpoint device is active. That is, the audio
+ // Retrieve the IMMDevice by using the specified role or the specified
+ // unique endpoint device-identification string.
+ // TODO(henrika): possibly add suport for the eCommunications as well.
+ if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
+ // Retrieve the default capture audio endpoint for the specified role.
+ // Note that, in Windows Vista, the MMDevice API supports device roles
+ // but the system-supplied user interface programs do not.
+ hr = enumerator->GetDefaultAudioEndpoint(eCapture,
+ eConsole,
+ endpoint_device_.Receive());
+ } else {
+ // Retrieve a capture endpoint device that is specified by an endpoint
+ // device-identification string.
+ hr = enumerator->GetDevice(UTF8ToUTF16(device_id_).c_str(),
+ endpoint_device_.Receive());
+ }
+
+ if (FAILED(hr))
+ return hr;
+
+ // Verify that the audio endpoint device is active, i.e., the audio
// adapter that connects to the endpoint device is present and enabled.
DWORD state = DEVICE_STATE_DISABLED;
hr = endpoint_device_->GetState(&state);
diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h
index e255061..ebaab93 100644
--- a/media/audio/win/audio_low_latency_input_win.h
+++ b/media/audio/win/audio_low_latency_input_win.h
@@ -78,7 +78,7 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// the audio manager who is creating this object.
WASAPIAudioInputStream(AudioManagerWin* manager,
const AudioParameters& params,
- ERole device_role);
+ const std::string& device_id);
// The dtor is typically called by the AudioManager only and it is usually
// triggered by calling AudioInputStream::Close().
virtual ~WASAPIAudioInputStream();
@@ -103,7 +103,7 @@ class MEDIA_EXPORT WASAPIAudioInputStream
void HandleError(HRESULT err);
// The Open() method is divided into these sub methods.
- HRESULT SetCaptureDevice(ERole device_role);
+ HRESULT SetCaptureDevice();
HRESULT ActivateCaptureDevice();
HRESULT GetAudioEngineStreamFormat();
bool DesiredFormatIsSupported();
@@ -145,8 +145,10 @@ class MEDIA_EXPORT WASAPIAudioInputStream
// Length of the audio endpoint buffer.
size_t endpoint_buffer_size_frames_;
- // Defines the role that the system has assigned to an audio endpoint device.
- ERole device_role_;
+ // Contains the unique name of the selected endpoint device.
+ // Note that AudioManagerBase::kDefaultDeviceId represents the default
+ // device role and is not a valid ID as such.
+ std::string device_id_;
// Conversion factor used in delay-estimation calculations.
// Converts a raw performance counter value to 100-nanosecond unit.
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index 9d38588..158053f 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -165,21 +165,15 @@ AudioInputStream* AudioManagerWin::MakeAudioInputStream(
return FakeAudioInputStream::MakeFakeStream(params);
} else if (params.format == AudioParameters::AUDIO_PCM_LINEAR) {
return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
- WAVE_MAPPER);
+ AudioManagerBase::kDefaultDeviceId);
} else if (params.format == AudioParameters::AUDIO_PCM_LOW_LATENCY) {
if (!media::IsWASAPISupported()) {
// Fall back to Windows Wave implementation on Windows XP or lower.
DLOG(INFO) << "Using WaveIn since WASAPI requires at least Vista.";
- // TODO(xians): Handle the non-default device.
- if (device_id == AudioManagerBase::kDefaultDeviceId)
- return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
- WAVE_MAPPER);
+ return new PCMWaveInAudioInputStream(this, params, kNumInputBuffers,
+ device_id);
} else {
- // TODO(henrika): improve possibility to specify audio endpoint.
- // Use the default device (same as for Wave) for now to be compatible.
- // TODO(xians): Handle the non-default device.
- if (device_id == AudioManagerBase::kDefaultDeviceId)
- return new WASAPIAudioInputStream(this, params, eConsole);
+ return new WASAPIAudioInputStream(this, params, device_id);
}
}
return NULL;
diff --git a/media/audio/win/wavein_input_win.cc b/media/audio/win/wavein_input_win.cc
index d9f600b..d3f1162 100644
--- a/media/audio/win/wavein_input_win.cc
+++ b/media/audio/win/wavein_input_win.cc
@@ -12,11 +12,14 @@
#include "media/audio/audio_io.h"
#include "media/audio/audio_util.h"
#include "media/audio/win/audio_manager_win.h"
+#include "media/audio/win/device_enumeration_win.h"
namespace {
const int kStopInputStreamCallbackTimeout = 3000; // Three seconds.
}
+using media::AudioDeviceNames;
+
// Our sound buffers are allocated once and kept in a linked list using the
// the WAVEHDR::dwUser variable. The last buffer points to the first buffer.
static WAVEHDR* GetNextBuffer(WAVEHDR* current) {
@@ -25,7 +28,7 @@ static WAVEHDR* GetNextBuffer(WAVEHDR* current) {
PCMWaveInAudioInputStream::PCMWaveInAudioInputStream(
AudioManagerWin* manager, const AudioParameters& params, int num_buffers,
- UINT device_id)
+ const std::string& device_id)
: state_(kStateEmpty),
manager_(manager),
device_id_(device_id),
@@ -58,10 +61,20 @@ bool PCMWaveInAudioInputStream::Open() {
return false;
if (num_buffers_ < 2 || num_buffers_ > 10)
return false;
- MMRESULT result = ::waveInOpen(&wavein_, device_id_, &format_,
- reinterpret_cast<DWORD_PTR>(WaveCallback),
- reinterpret_cast<DWORD_PTR>(this),
- CALLBACK_FUNCTION);
+
+ // Convert the stored device id string into an unsigned integer
+ // corresponding to the selected device.
+ UINT device_id = WAVE_MAPPER;
+ if (!GetDeviceId(&device_id)) {
+ return false;
+ }
+
+ // Open the specified input device for recording.
+ MMRESULT result = MMSYSERR_NOERROR;
+ result = ::waveInOpen(&wavein_, device_id, &format_,
+ reinterpret_cast<DWORD_PTR>(WaveCallback),
+ reinterpret_cast<DWORD_PTR>(this),
+ CALLBACK_FUNCTION);
if (result != MMSYSERR_NOERROR)
return false;
@@ -185,6 +198,41 @@ void PCMWaveInAudioInputStream::QueueNextPacket(WAVEHDR *buffer) {
HandleError(res);
}
+bool PCMWaveInAudioInputStream::GetDeviceId(UINT* device_index) {
+ // Deliver the default input device id (WAVE_MAPPER) if the default
+ // device has been selected.
+ if (device_id_ == AudioManagerBase::kDefaultDeviceId) {
+ *device_index = WAVE_MAPPER;
+ return true;
+ }
+
+ // Get list of all available and active devices.
+ AudioDeviceNames device_names;
+ if (!GetInputDeviceNamesWinXP(&device_names))
+ return false;
+
+ if (device_names.empty())
+ return false;
+
+ // Search the full list of devices and compare with the specified
+ // device id which was specified in the constructor. Stop comparing
+ // when a match is found and return the corresponding index.
+ UINT index = 0;
+ bool found_device = false;
+ AudioDeviceNames::const_iterator it = device_names.begin();
+ while (it != device_names.end()) {
+ if (it->unique_id.compare(device_id_) == 0) {
+ *device_index = index;
+ found_device = true;
+ break;
+ }
+ ++index;
+ ++it;
+ }
+
+ return found_device;
+}
+
// Windows calls us back in this function when some events happen. Most notably
// when it has an audio buffer with recorded data.
void PCMWaveInAudioInputStream::WaveCallback(HWAVEIN hwi, UINT msg,
diff --git a/media/audio/win/wavein_input_win.h b/media/audio/win/wavein_input_win.h
index c16a4a7..ab8b95a 100644
--- a/media/audio/win/wavein_input_win.h
+++ b/media/audio/win/wavein_input_win.h
@@ -24,7 +24,7 @@ class PCMWaveInAudioInputStream : public AudioInputStream {
PCMWaveInAudioInputStream(AudioManagerWin* manager,
const AudioParameters& params,
int num_buffers,
- UINT device_id);
+ const std::string& device_id);
virtual ~PCMWaveInAudioInputStream();
// Implementation of AudioInputStream.
@@ -61,6 +61,10 @@ class PCMWaveInAudioInputStream : public AudioInputStream {
// Sends a buffer to the audio driver for recording.
void QueueNextPacket(WAVEHDR* buffer);
+ // Converts the stored device id string into an unsigned integer which
+ // can be used by waveInOpen() to open the specified capture device.
+ bool GetDeviceId(UINT* device_index);
+
// Reader beware. Visual C has stronger guarantees on volatile vars than
// most people expect. In fact, it has release semantics on write and
// acquire semantics on reads. See the msdn documentation.
@@ -82,9 +86,10 @@ class PCMWaveInAudioInputStream : public AudioInputStream {
// Channels, 1 or 2.
const int channels_;
- // The id assigned by the operating system to the selected wave output
- // hardware device. Usually this is just -1 which means 'default device'.
- UINT device_id_;
+ // Contains the unique name of the selected endpoint device.
+ // Note that AudioManagerBase::kDefaultDeviceId represents the default
+ // device role and is not a valid ID as such.
+ std::string device_id_;
// Windows native structure to encode the format parameters.
WAVEFORMATEX format_;