Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(129)

Unified Diff: media/audio/win/core_audio_util_win.cc

Issue 1060673002: Disable low latency audio under remote desktop sessions. (Closed) Base URL: http://chromium.googlesource.com/chromium/src.git@master
Patch Set: Disable for remote audio, on Open() too. Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/win/core_audio_util_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/audio/win/core_audio_util_win.cc
diff --git a/media/audio/win/core_audio_util_win.cc b/media/audio/win/core_audio_util_win.cc
index b56d6e6a6e13f9ef749ec4ac57c5e5111c102164..b3bc62fb8bc867c1a08275461d8d966453090d85 100644
--- a/media/audio/win/core_audio_util_win.cc
+++ b/media/audio/win/core_audio_util_win.cc
@@ -136,18 +136,6 @@ static bool LoadAudiosesDll() {
return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL);
}
-static bool CanCreateDeviceEnumerator() {
- ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
- HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
- NULL, CLSCTX_INPROC_SERVER);
-
- // If we hit CO_E_NOTINITIALIZED, CoInitialize has not been called and it
- // must be called at least once for each thread that uses the COM library.
- CHECK_NE(hr, CO_E_NOTINITIALIZED);
-
- return SUCCEEDED(hr);
-}
-
static std::string GetDeviceID(IMMDevice* device) {
ScopedCoMem<WCHAR> device_id_com;
std::string device_id;
@@ -156,7 +144,68 @@ static std::string GetDeviceID(IMMDevice* device) {
return device_id;
}
-bool CoreAudioUtil::IsSupported() {
+static HRESULT GetDeviceFriendlyNameInternal(IMMDevice* device,
+ std::string* friendly_name) {
+ // Retrieve user-friendly name of endpoint device.
+ // Example: "Microphone (Realtek High Definition Audio)".
+ ScopedComPtr<IPropertyStore> properties;
+ HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
+ if (FAILED(hr))
+ return hr;
+
+ base::win::ScopedPropVariant friendly_name_pv;
+ hr = properties->GetValue(PKEY_Device_FriendlyName,
+ friendly_name_pv.Receive());
+ if (FAILED(hr))
+ return hr;
+
+ if (friendly_name_pv.get().vt == VT_LPWSTR &&
+ friendly_name_pv.get().pwszVal) {
+ base::WideToUTF8(friendly_name_pv.get().pwszVal,
+ wcslen(friendly_name_pv.get().pwszVal), friendly_name);
+ }
+
+ return hr;
+}
+
+static ScopedComPtr<IMMDeviceEnumerator> CreateDeviceEnumeratorInternal() {
+ ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
+ HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
+ NULL, CLSCTX_INPROC_SERVER);
+ if (hr == CO_E_NOTINITIALIZED) {
+ LOG(ERROR) << "CoCreateInstance fails with CO_E_NOTINITIALIZED";
+ // We have seen crashes which indicates that this method can in fact
+ // fail with CO_E_NOTINITIALIZED in combination with certain 3rd party
+ // modules. Calling CoInitializeEx is an attempt to resolve the reported
+ // issues. See http://crbug.com/378465 for details.
+ hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
henrika (OOO until Aug 14) 2015/04/07 07:41:08 I hope Tommi can comment on this part.
DaleCurtis 2015/04/07 22:24:54 Can you elaborate on your question? I think it was
henrika (OOO until Aug 14) 2015/04/08 06:57:36 I think you are correct but maybe Tommi has a seco
+ if (SUCCEEDED(hr)) {
+ hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
+ NULL, CLSCTX_INPROC_SERVER);
+ }
+ }
+ return device_enumerator;
+}
+
+static bool IsRemoteSession() {
+ return !!GetSystemMetrics(SM_REMOTESESSION);
+}
+
+static bool IsRemoteDeviceInternal(IMMDevice* device) {
+ DCHECK(IsRemoteSession());
+
+ std::string device_name;
+ HRESULT hr = GetDeviceFriendlyNameInternal(device, &device_name);
+
+ // This method should only be called if IsRemoteSession() is true, so assume
+ // we have a remote audio device if we can't tell.
+ if (FAILED(hr))
+ return true;
+
+ return device_name == "Remote Audio";
henrika (OOO until Aug 14) 2015/04/07 07:41:08 Any reference to how we know that this is always t
DaleCurtis 2015/04/07 22:24:54 Couldn't find any reference. I have no idea if "Re
henrika (OOO until Aug 14) 2015/04/08 06:57:36 Acknowledged.
+}
+
+static bool IsSupportedInternal() {
// It is possible to force usage of WaveXxx APIs by using a command line flag.
const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
if (cmd_line->HasSwitch(switches::kForceWaveAudio)) {
@@ -176,19 +225,47 @@ bool CoreAudioUtil::IsSupported() {
// the Audioses DLL since it depends on Mmdevapi.dll.
// See http://crbug.com/166397 why this extra step is required to guarantee
// Core Audio support.
- static bool g_audioses_dll_available = LoadAudiosesDll();
- if (!g_audioses_dll_available)
+ if (!LoadAudiosesDll())
return false;
// Being able to load the Audioses.dll does not seem to be sufficient for
// all devices to guarantee Core Audio support. To be 100%, we also verify
// that it is possible to a create the IMMDeviceEnumerator interface. If this
// works as well we should be home free.
- static bool g_can_create_device_enumerator = CanCreateDeviceEnumerator();
- LOG_IF(ERROR, !g_can_create_device_enumerator)
- << "Failed to create Core Audio device enumerator on thread with ID "
- << GetCurrentThreadId();
- return g_can_create_device_enumerator;
+ ScopedComPtr<IMMDeviceEnumerator> device_enumerator =
+ CreateDeviceEnumeratorInternal();
+ if (!device_enumerator) {
+ LOG(ERROR)
+ << "Failed to create Core Audio device enumerator on thread with ID "
+ << GetCurrentThreadId();
+ return false;
+ }
+
+ // Don't use CoreAudio when a remote desktop session with remote audio is
+ // present; several users report only WaveAudio working for them and crash
+ // reports show hangs when calling into the OS for CoreAudio API calls. See
+ // http://crbug.com/422522 and http://crbug.com/180591.
+ //
+ // Note: There's another check in WASAPIAudioOutputStream::Open() for the case
+ // where a remote session is created after Chrome has been started. Graceful
+ // fallback to WaveOut will occur in this case via AudioOutputResampler.
+ if (!IsRemoteSession())
+ return true;
+
+ ScopedComPtr<IMMDevice> device;
+ HRESULT hr = device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole,
+ device.Receive());
+
+ // Assume remote audio playback if we can't tell.
+ if (FAILED(hr))
henrika (OOO until Aug 14) 2015/04/07 07:41:08 Do we need this check? Is it not included in IsRem
DaleCurtis 2015/04/07 22:24:54 Seems GetDefaultAudioEndpoint could still fail? th
henrika (OOO until Aug 14) 2015/04/08 06:57:36 Acknowledged.
+ return false;
+
+ return !IsRemoteDeviceInternal(device.get());
+}
+
+bool CoreAudioUtil::IsSupported() {
+ static bool g_is_supported = IsSupportedInternal();
+ return g_is_supported;
}
base::TimeDelta CoreAudioUtil::RefererenceTimeToTimeDelta(REFERENCE_TIME time) {
@@ -233,22 +310,9 @@ int CoreAudioUtil::NumberOfActiveDevices(EDataFlow data_flow) {
ScopedComPtr<IMMDeviceEnumerator> CoreAudioUtil::CreateDeviceEnumerator() {
DCHECK(IsSupported());
- ScopedComPtr<IMMDeviceEnumerator> device_enumerator;
- HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
- NULL, CLSCTX_INPROC_SERVER);
- if (hr == CO_E_NOTINITIALIZED) {
- LOG(ERROR) << "CoCreateInstance fails with CO_E_NOTINITIALIZED";
- // We have seen crashes which indicates that this method can in fact
- // fail with CO_E_NOTINITIALIZED in combination with certain 3rd party
- // modules. Calling CoInitializeEx is an attempt to resolve the reported
- // issues. See http://crbug.com/378465 for details.
- hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
- if (SUCCEEDED(hr)) {
- hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator),
- NULL, CLSCTX_INPROC_SERVER);
- }
- }
- CHECK(SUCCEEDED(hr));
+ ScopedComPtr<IMMDeviceEnumerator> device_enumerator =
+ CreateDeviceEnumeratorInternal();
+ CHECK(device_enumerator);
return device_enumerator;
}
@@ -323,21 +387,9 @@ HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) {
if (device_name.unique_id.empty())
return E_FAIL;
- // Retrieve user-friendly name of endpoint device.
- // Example: "Microphone (Realtek High Definition Audio)".
- ScopedComPtr<IPropertyStore> properties;
- HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive());
- if (FAILED(hr))
- return hr;
- base::win::ScopedPropVariant friendly_name;
- hr = properties->GetValue(PKEY_Device_FriendlyName, friendly_name.Receive());
+ HRESULT hr = GetDeviceFriendlyNameInternal(device, &device_name.device_name);
if (FAILED(hr))
return hr;
- if (friendly_name.get().vt == VT_LPWSTR && friendly_name.get().pwszVal) {
- base::WideToUTF8(friendly_name.get().pwszVal,
- wcslen(friendly_name.get().pwszVal),
- &device_name.device_name);
- }
*name = device_name;
DVLOG(2) << "friendly name: " << device_name.device_name;
@@ -854,4 +906,15 @@ bool CoreAudioUtil::FillRenderEndpointBufferWithSilence(
AUDCLNT_BUFFERFLAGS_SILENT));
}
+bool CoreAudioUtil::IsRemoteOutputDevice(const std::string& device_id) {
+ DCHECK(IsSupported());
+ if (!IsRemoteSession())
+ return false;
+ ScopedComPtr<IMMDevice> device(device_id.empty()
+ ? CreateDefaultDevice(eRender, eConsole)
+ : CreateDevice(device_id));
+ // Assume remote audio if we can't tell.
+ return device ? IsRemoteDeviceInternal(device.get()) : true;
+}
+
} // namespace media
« no previous file with comments | « media/audio/win/core_audio_util_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698