summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authordalecurtis <dalecurtis@chromium.org>2015-07-02 10:22:43 -0700
committerCommit bot <commit-bot@chromium.org>2015-07-02 17:23:22 +0000
commit8afde271c7445ad8700ebfefda72601122cb4d86 (patch)
tree0f6a71087de4f0ce5182d3e756533e3898897729 /media
parent9d02fb0d79f255dbaf8e8613ee829d8875ae561d (diff)
downloadchromium_src-8afde271c7445ad8700ebfefda72601122cb4d86.zip
chromium_src-8afde271c7445ad8700ebfefda72601122cb4d86.tar.gz
chromium_src-8afde271c7445ad8700ebfefda72601122cb4d86.tar.bz2
Unify audio device input parameter selection on Windows.
The old code path is largely superseded by the functionality added to CoreAudioUtil, but lacks things like "active device checks" which may be contributing to hanging audio threads in the wild. This patch removes all the old paths and cleans up the new paths for consistency and code resuse. BUG=422522 TEST=input capture still works Review URL: https://codereview.chromium.org/1220493003 Cr-Commit-Position: refs/heads/master@{#337238}
Diffstat (limited to 'media')
-rw-r--r--media/audio/win/audio_low_latency_input_win.cc85
-rw-r--r--media/audio/win/audio_low_latency_input_win.h11
-rw-r--r--media/audio/win/audio_low_latency_input_win_unittest.cc14
-rw-r--r--media/audio/win/audio_manager_win.cc20
-rw-r--r--media/audio/win/core_audio_util_win.cc76
-rw-r--r--media/audio/win/core_audio_util_win.h4
6 files changed, 87 insertions, 123 deletions
diff --git a/media/audio/win/audio_low_latency_input_win.cc b/media/audio/win/audio_low_latency_input_win.cc
index d782523..66792fc 100644
--- a/media/audio/win/audio_low_latency_input_win.cc
+++ b/media/audio/win/audio_low_latency_input_win.cc
@@ -16,24 +16,6 @@ using base::win::ScopedComPtr;
using base::win::ScopedCOMInitializer;
namespace media {
-namespace {
-
-// Returns true if |device| represents the default communication capture device.
-bool IsDefaultCommunicationDevice(IMMDeviceEnumerator* enumerator,
- IMMDevice* device) {
- ScopedComPtr<IMMDevice> communications;
- if (FAILED(enumerator->GetDefaultAudioEndpoint(eCapture, eCommunications,
- communications.Receive()))) {
- return false;
- }
-
- base::win::ScopedCoMem<WCHAR> communications_id, device_id;
- device->GetId(&device_id);
- communications->GetId(&communications_id);
- return lstrcmpW(communications_id, device_id) == 0;
-}
-
-} // namespace
WASAPIAudioInputStream::WASAPIAudioInputStream(AudioManagerWin* manager,
const AudioParameters& params,
@@ -283,73 +265,6 @@ bool WASAPIAudioInputStream::IsMuted() {
return is_muted != FALSE;
}
-// static
-AudioParameters WASAPIAudioInputStream::GetInputStreamParameters(
- const std::string& device_id) {
- int sample_rate = 48000;
- ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO;
-
- base::win::ScopedCoMem<WAVEFORMATEX> audio_engine_mix_format;
- int effects = AudioParameters::NO_EFFECTS;
- if (SUCCEEDED(GetMixFormat(device_id, &audio_engine_mix_format, &effects))) {
- sample_rate = static_cast<int>(audio_engine_mix_format->nSamplesPerSec);
- channel_layout = audio_engine_mix_format->nChannels == 1 ?
- CHANNEL_LAYOUT_MONO : CHANNEL_LAYOUT_STEREO;
- }
-
- // Use 10ms frame size as default.
- int frames_per_buffer = sample_rate / 100;
- return AudioParameters(
- AudioParameters::AUDIO_PCM_LOW_LATENCY, channel_layout, sample_rate,
- 16, frames_per_buffer, effects);
-}
-
-// static
-HRESULT WASAPIAudioInputStream::GetMixFormat(const std::string& device_id,
- WAVEFORMATEX** device_format,
- int* effects) {
- DCHECK(effects);
-
- // It is assumed that this static method is called from a COM thread, i.e.,
- // CoInitializeEx() is not called here to avoid STA/MTA conflicts.
- ScopedComPtr<IMMDeviceEnumerator> enumerator;
- HRESULT hr = enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), NULL,
- CLSCTX_INPROC_SERVER);
- if (FAILED(hr))
- return hr;
-
- ScopedComPtr<IMMDevice> endpoint_device;
- if (device_id == AudioManagerBase::kDefaultDeviceId) {
- // Retrieve the default capture audio endpoint.
- hr = enumerator->GetDefaultAudioEndpoint(eCapture, eConsole,
- endpoint_device.Receive());
- } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) {
- // Get the mix format of the default playback stream.
- hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
- endpoint_device.Receive());
- } else {
- // Retrieve a capture endpoint device that is specified by an endpoint
- // device-identification string.
- hr = enumerator->GetDevice(base::UTF8ToUTF16(device_id).c_str(),
- endpoint_device.Receive());
- }
-
- if (FAILED(hr))
- return hr;
-
- *effects =
- IsDefaultCommunicationDevice(enumerator.get(), endpoint_device.get())
- ? AudioParameters::DUCKING
- : AudioParameters::NO_EFFECTS;
-
- ScopedComPtr<IAudioClient> audio_client;
- hr = endpoint_device->Activate(__uuidof(IAudioClient),
- CLSCTX_INPROC_SERVER,
- NULL,
- audio_client.ReceiveVoid());
- return SUCCEEDED(hr) ? audio_client->GetMixFormat(device_format) : hr;
-}
-
void WASAPIAudioInputStream::Run() {
ScopedCOMInitializer com_init(ScopedCOMInitializer::kMTA);
diff --git a/media/audio/win/audio_low_latency_input_win.h b/media/audio/win/audio_low_latency_input_win.h
index 7501405..f88b8dd 100644
--- a/media/audio/win/audio_low_latency_input_win.h
+++ b/media/audio/win/audio_low_latency_input_win.h
@@ -106,9 +106,6 @@ class MEDIA_EXPORT WASAPIAudioInputStream
bool started() const { return started_; }
- // Returns the default hardware audio parameters of the specific device.
- static AudioParameters GetInputStreamParameters(const std::string& device_id);
-
private:
// DelegateSimpleThread::Delegate implementation.
void Run() override;
@@ -123,14 +120,6 @@ class MEDIA_EXPORT WASAPIAudioInputStream
bool DesiredFormatIsSupported();
HRESULT InitializeAudioEngine();
- // Retrieves the stream format that the audio engine uses for its internal
- // processing/mixing of shared-mode streams.
- // |effects| is a an AudioParameters::effects() flag that will have the
- // DUCKING flag raised for only the default communication device.
- static HRESULT GetMixFormat(const std::string& device_id,
- WAVEFORMATEX** device_format,
- int* effects);
-
// Our creator, the audio manager needs to be notified when we close.
AudioManagerWin* manager_;
diff --git a/media/audio/win/audio_low_latency_input_win_unittest.cc b/media/audio/win/audio_low_latency_input_win_unittest.cc
index 4f01654..a915b4d 100644
--- a/media/audio/win/audio_low_latency_input_win_unittest.cc
+++ b/media/audio/win/audio_low_latency_input_win_unittest.cc
@@ -162,10 +162,9 @@ static bool HasCoreAudioAndInputDevices(AudioManager* audio_man) {
class AudioInputStreamWrapper {
public:
explicit AudioInputStreamWrapper(AudioManager* audio_manager)
- : audio_man_(audio_manager),
- default_params_(
- audio_manager->GetInputStreamParameters(
- AudioManagerBase::kDefaultDeviceId)) {
+ : audio_man_(audio_manager) {
+ EXPECT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
+ AudioManagerBase::kDefaultDeviceId, false, &default_params_)));
EXPECT_EQ(format(), AudioParameters::AUDIO_PCM_LOW_LATENCY);
frames_per_buffer_ = default_params_.frames_per_buffer();
// We expect the default buffer size to be a 10ms buffer.
@@ -206,7 +205,7 @@ class AudioInputStreamWrapper {
}
AudioManager* audio_man_;
- const AudioParameters default_params_;
+ AudioParameters default_params_;
int frames_per_buffer_;
};
@@ -265,8 +264,9 @@ TEST(WinAudioInputTest, WASAPIAudioInputStreamHardwareSampleRate) {
for (media::AudioDeviceNames::const_iterator it = device_names.begin();
it != device_names.end(); ++it) {
// Retrieve the hardware sample rate given a specified audio input device.
- AudioParameters params = WASAPIAudioInputStream::GetInputStreamParameters(
- it->unique_id);
+ AudioParameters params;
+ ASSERT_TRUE(SUCCEEDED(CoreAudioUtil::GetPreferredAudioParameters(
+ it->unique_id, false, &params)));
EXPECT_GE(params.sample_rate(), 0);
}
}
diff --git a/media/audio/win/audio_manager_win.cc b/media/audio/win/audio_manager_win.cc
index c09fb46..344a5d7 100644
--- a/media/audio/win/audio_manager_win.cc
+++ b/media/audio/win/audio_manager_win.cc
@@ -303,14 +303,18 @@ void AudioManagerWin::GetAudioOutputDeviceNames(
AudioParameters AudioManagerWin::GetInputStreamParameters(
const std::string& device_id) {
+ HRESULT hr = E_FAIL;
AudioParameters parameters;
- if (!core_audio_supported()) {
+ if (core_audio_supported()) {
+ hr = CoreAudioUtil::GetPreferredAudioParameters(device_id, false,
+ &parameters);
+ }
+
+ if (FAILED(hr) || !parameters.IsValid()) {
// Windows Wave implementation is being used.
parameters = AudioParameters(
- AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 48000,
- 16, kFallbackBufferSize, AudioParameters::NO_EFFECTS);
- } else {
- parameters = WASAPIAudioInputStream::GetInputStreamParameters(device_id);
+ AudioParameters::AUDIO_PCM_LINEAR, CHANNEL_LAYOUT_STEREO, 48000, 16,
+ kFallbackBufferSize, AudioParameters::NO_EFFECTS);
}
int user_buffer_size = GetUserBufferSize();
@@ -440,9 +444,9 @@ AudioParameters AudioManagerWin::GetPreferredOutputStreamParameters(
} else {
AudioParameters params;
HRESULT hr = CoreAudioUtil::GetPreferredAudioParameters(
- output_device_id.empty() ?
- GetDefaultOutputDeviceID() : output_device_id,
- &params);
+ output_device_id.empty() ? GetDefaultOutputDeviceID()
+ : output_device_id,
+ true, &params);
if (SUCCEEDED(hr)) {
bits_per_sample = params.bits_per_sample();
buffer_size = params.frames_per_buffer();
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index 6c9a8c7..ce1793e 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -15,6 +15,7 @@
#include "base/win/scoped_handle.h"
#include "base/win/scoped_propvariant.h"
#include "base/win/windows_version.h"
+#include "media/audio/audio_manager_base.h"
#include "media/base/media_switches.h"
using base::win::ScopedCoMem;
@@ -143,6 +144,11 @@ static std::string GetDeviceID(IMMDevice* device) {
return device_id;
}
+static bool IsDeviceActive(IMMDevice* device) {
+ DWORD state = DEVICE_STATE_DISABLED;
+ return SUCCEEDED(device->GetState(&state)) && (state & DEVICE_STATE_ACTIVE);
+}
+
static HRESULT GetDeviceFriendlyNameInternal(IMMDevice* device,
std::string* friendly_name) {
// Retrieve user-friendly name of endpoint device.
@@ -303,13 +309,9 @@ ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow,
// Verify that the audio endpoint device is active, i.e., that the audio
// adapter that connects to the endpoint device is present and enabled.
- DWORD state = DEVICE_STATE_DISABLED;
- hr = endpoint_device->GetState(&state);
- if (SUCCEEDED(hr)) {
- if (!(state & DEVICE_STATE_ACTIVE)) {
- DVLOG(1) << "Selected endpoint device is not active";
- endpoint_device.Release();
- }
+ if (!IsDeviceActive(endpoint_device.get())) {
+ DVLOG(1) << "Selected endpoint device is not active";
+ endpoint_device.Release();
}
return endpoint_device;
}
@@ -337,6 +339,18 @@ ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice(
base::UTF8ToUTF16(device_id).c_str(), endpoint_device.Receive());
DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: "
<< std::hex << hr;
+
+ if (FAILED(hr)) {
+ DVLOG(1) << "IMMDeviceEnumerator::GetDevice: " << std::hex << hr;
+ return endpoint_device;
+ }
+
+ // Verify that the audio endpoint device is active, i.e., that the audio
+ // adapter that connects to the endpoint device is present and enabled.
+ if (!IsDeviceActive(endpoint_device.get())) {
+ DVLOG(1) << "Selected endpoint device is not active";
+ endpoint_device.Release();
+ }
return endpoint_device;
}
@@ -722,10 +736,22 @@ HRESULT CoreAudioUtil::GetPreferredAudioParameters(
return hr;
}
-HRESULT CoreAudioUtil::GetPreferredAudioParameters(
- const std::string& device_id, AudioParameters* params) {
+HRESULT CoreAudioUtil::GetPreferredAudioParameters(const std::string& device_id,
+ bool is_output_device,
+ AudioParameters* params) {
DCHECK(IsSupported());
- ScopedComPtr<IMMDevice> device(CreateDevice(device_id));
+
+ ScopedComPtr<IMMDevice> device;
+ if (device_id == AudioManagerBase::kDefaultDeviceId) {
+ device = CoreAudioUtil::CreateDefaultDevice(
+ is_output_device ? eRender : eCapture, eConsole);
+ } else if (device_id == AudioManagerBase::kLoopbackInputDeviceId) {
+ DCHECK(!is_output_device);
+ device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole);
+ } else {
+ device = CreateDevice(device_id);
+ }
+
if (!device.get()) {
// Map NULL-pointer to new error code which can be different from the
// actual error code. The exact value is not important here.
@@ -738,7 +764,35 @@ HRESULT CoreAudioUtil::GetPreferredAudioParameters(
// actual error code. The exact value is not important here.
return AUDCLNT_E_ENDPOINT_CREATE_FAILED;
}
- return GetPreferredAudioParameters(client.get(), params);
+
+ HRESULT hr = GetPreferredAudioParameters(client.get(), params);
+ if (FAILED(hr) || is_output_device || !params->IsValid())
+ return hr;
+
+ // The following functionality is only for input devices.
+ DCHECK(!is_output_device);
+
+ // TODO(dalecurtis): Old code rewrote != 1 channels to stereo, do we still
+ // need to do the same thing?
+ if (params->channels() != 1) {
+ params->Reset(params->format(), CHANNEL_LAYOUT_STEREO, 2,
+ params->sample_rate(), params->bits_per_sample(),
+ params->frames_per_buffer());
+ }
+
+ ScopedComPtr<IMMDevice> communications_device(
+ CreateDefaultDevice(eCapture, eCommunications));
+ if (communications_device &&
+ GetDeviceID(communications_device.get()) == GetDeviceID(device.get())) {
+ // Raise the 'DUCKING' flag for default communication devices.
+ *params =
+ AudioParameters(params->format(), params->channel_layout(),
+ params->channels(), params->sample_rate(),
+ params->bits_per_sample(), params->frames_per_buffer(),
+ params->effects() | AudioParameters::DUCKING);
+ }
+
+ return hr;
}
ChannelConfig CoreAudioUtil::GetChannelConfig(const std::string& device_id,
diff --git a/media/audio/win/core_audio_util_win.h b/media/audio/win/core_audio_util_win.h
index 4e93531..d91d18c 100644
--- a/media/audio/win/core_audio_util_win.h
+++ b/media/audio/win/core_audio_util_win.h
@@ -174,9 +174,11 @@ class MEDIA_EXPORT CoreAudioUtil {
// there are no preferred settings for an exclusive mode stream.
static HRESULT GetPreferredAudioParameters(IAudioClient* client,
AudioParameters* params);
- static HRESULT GetPreferredAudioParameters(EDataFlow data_flow, ERole role,
+ static HRESULT GetPreferredAudioParameters(EDataFlow data_flow,
+ ERole role,
AudioParameters* params);
static HRESULT GetPreferredAudioParameters(const std::string& device_id,
+ bool is_output_device,
AudioParameters* params);
// Retrieves an integer mask which corresponds to the channel layout the