| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "media/audio/win/core_audio_util_win.h" | 5 #include "media/audio/win/core_audio_util_win.h" |
| 6 | 6 |
| 7 #include <audioclient.h> | 7 #include <audioclient.h> |
| 8 #include <devicetopology.h> | 8 #include <devicetopology.h> |
| 9 #include <functiondiscoverykeys_devpkey.h> | 9 #include <functiondiscoverykeys_devpkey.h> |
| 10 | 10 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 180 // issues. See http://crbug.com/378465 for details. | 180 // issues. See http://crbug.com/378465 for details. |
| 181 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); | 181 hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); |
| 182 if (SUCCEEDED(hr)) { | 182 if (SUCCEEDED(hr)) { |
| 183 hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), | 183 hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), |
| 184 NULL, CLSCTX_INPROC_SERVER); | 184 NULL, CLSCTX_INPROC_SERVER); |
| 185 } | 185 } |
| 186 } | 186 } |
| 187 return device_enumerator; | 187 return device_enumerator; |
| 188 } | 188 } |
| 189 | 189 |
| 190 static bool IsRemoteSession() { | |
| 191 return !!GetSystemMetrics(SM_REMOTESESSION); | |
| 192 } | |
| 193 | |
| 194 static bool IsRemoteDeviceInternal(IMMDevice* device) { | |
| 195 DCHECK(IsRemoteSession()); | |
| 196 | |
| 197 std::string device_name; | |
| 198 HRESULT hr = GetDeviceFriendlyNameInternal(device, &device_name); | |
| 199 | |
| 200 // This method should only be called if IsRemoteSession() is true, so assume | |
| 201 // we have a remote audio device if we can't tell. | |
| 202 if (FAILED(hr)) | |
| 203 return true; | |
| 204 | |
| 205 return device_name == "Remote Audio"; | |
| 206 } | |
| 207 | |
| 208 static bool IsSupportedInternal() { | 190 static bool IsSupportedInternal() { |
| 209 // It is possible to force usage of WaveXxx APIs by using a command line flag. | 191 // It is possible to force usage of WaveXxx APIs by using a command line flag. |
| 210 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 192 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 211 if (cmd_line->HasSwitch(switches::kForceWaveAudio)) { | 193 if (cmd_line->HasSwitch(switches::kForceWaveAudio)) { |
| 212 DVLOG(1) << "Forcing usage of Windows WaveXxx APIs"; | 194 DVLOG(1) << "Forcing usage of Windows WaveXxx APIs"; |
| 213 return false; | 195 return false; |
| 214 } | 196 } |
| 215 | 197 |
| 216 // Microsoft does not plan to make the Core Audio APIs available for use | 198 // Microsoft does not plan to make the Core Audio APIs available for use |
| 217 // with earlier versions of Windows, including Microsoft Windows Server 2003, | 199 // with earlier versions of Windows, including Microsoft Windows Server 2003, |
| (...skipping 16 matching lines...) Expand all Loading... |
| 234 // works as well we should be home free. | 216 // works as well we should be home free. |
| 235 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 217 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 236 CreateDeviceEnumeratorInternal(); | 218 CreateDeviceEnumeratorInternal(); |
| 237 if (!device_enumerator) { | 219 if (!device_enumerator) { |
| 238 LOG(ERROR) | 220 LOG(ERROR) |
| 239 << "Failed to create Core Audio device enumerator on thread with ID " | 221 << "Failed to create Core Audio device enumerator on thread with ID " |
| 240 << GetCurrentThreadId(); | 222 << GetCurrentThreadId(); |
| 241 return false; | 223 return false; |
| 242 } | 224 } |
| 243 | 225 |
| 244 // Don't use CoreAudio when a remote desktop session with remote audio is | 226 return true; |
| 245 // present; several users report only WaveAudio working for them and crash | |
| 246 // reports show hangs when calling into the OS for CoreAudio API calls. See | |
| 247 // http://crbug.com/422522 and http://crbug.com/180591. | |
| 248 // | |
| 249 // Note: There's another check in WASAPIAudioOutputStream::Open() for the case | |
| 250 // where a remote session is created after Chrome has been started. Graceful | |
| 251 // fallback to WaveOut will occur in this case via AudioOutputResampler. | |
| 252 if (!IsRemoteSession()) | |
| 253 return true; | |
| 254 | |
| 255 ScopedComPtr<IMMDevice> device; | |
| 256 HRESULT hr = device_enumerator->GetDefaultAudioEndpoint(eRender, eConsole, | |
| 257 device.Receive()); | |
| 258 | |
| 259 // Assume remote audio playback if we can't tell. | |
| 260 if (FAILED(hr)) | |
| 261 return false; | |
| 262 | |
| 263 return !IsRemoteDeviceInternal(device.get()); | |
| 264 } | 227 } |
| 265 | 228 |
| 266 bool CoreAudioUtil::IsSupported() { | 229 bool CoreAudioUtil::IsSupported() { |
| 267 static bool g_is_supported = IsSupportedInternal(); | 230 static bool g_is_supported = IsSupportedInternal(); |
| 268 return g_is_supported; | 231 return g_is_supported; |
| 269 } | 232 } |
| 270 | 233 |
| 271 base::TimeDelta CoreAudioUtil::RefererenceTimeToTimeDelta(REFERENCE_TIME time) { | 234 base::TimeDelta CoreAudioUtil::RefererenceTimeToTimeDelta(REFERENCE_TIME time) { |
| 272 // Each unit of reference time is 100 nanoseconds <=> 0.1 microsecond. | 235 // Each unit of reference time is 100 nanoseconds <=> 0.1 microsecond. |
| 273 return base::TimeDelta::FromMicroseconds(0.1 * time + 0.5); | 236 return base::TimeDelta::FromMicroseconds(0.1 * time + 0.5); |
| (...skipping 625 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 899 if (FAILED(render_client->GetBuffer(num_frames_to_fill, &data))) | 862 if (FAILED(render_client->GetBuffer(num_frames_to_fill, &data))) |
| 900 return false; | 863 return false; |
| 901 | 864 |
| 902 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to | 865 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to |
| 903 // explicitly write silence data to the rendering buffer. | 866 // explicitly write silence data to the rendering buffer. |
| 904 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; | 867 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; |
| 905 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, | 868 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, |
| 906 AUDCLNT_BUFFERFLAGS_SILENT)); | 869 AUDCLNT_BUFFERFLAGS_SILENT)); |
| 907 } | 870 } |
| 908 | 871 |
| 909 bool CoreAudioUtil::IsRemoteOutputDevice(const std::string& device_id) { | |
| 910 DCHECK(IsSupported()); | |
| 911 if (!IsRemoteSession()) | |
| 912 return false; | |
| 913 ScopedComPtr<IMMDevice> device(device_id.empty() | |
| 914 ? CreateDefaultDevice(eRender, eConsole) | |
| 915 : CreateDevice(device_id)); | |
| 916 // Assume remote audio if we can't tell. | |
| 917 return device ? IsRemoteDeviceInternal(device.get()) : true; | |
| 918 } | |
| 919 | |
| 920 } // namespace media | 872 } // namespace media |
| OLD | NEW |