diff options
Diffstat (limited to 'media')
-rw-r--r-- | media/audio/win/audio_low_latency_input_win.cc | 43 | ||||
-rw-r--r-- | media/audio/win/audio_low_latency_input_win.h | 10 | ||||
-rw-r--r-- | media/audio/win/audio_manager_win.cc | 14 | ||||
-rw-r--r-- | media/audio/win/wavein_input_win.cc | 58 | ||||
-rw-r--r-- | media/audio/win/wavein_input_win.h | 13 |
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_; |