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 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
116 << ", nSamplesPerSec: " << format.Format.nSamplesPerSec | 116 << ", nSamplesPerSec: " << format.Format.nSamplesPerSec |
117 << ", nAvgBytesPerSec: " << format.Format.nAvgBytesPerSec | 117 << ", nAvgBytesPerSec: " << format.Format.nAvgBytesPerSec |
118 << ", nBlockAlign: " << format.Format.nBlockAlign | 118 << ", nBlockAlign: " << format.Format.nBlockAlign |
119 << ", wBitsPerSample: " << format.Format.wBitsPerSample | 119 << ", wBitsPerSample: " << format.Format.wBitsPerSample |
120 << ", cbSize: " << format.Format.cbSize | 120 << ", cbSize: " << format.Format.cbSize |
121 << ", wValidBitsPerSample: " << format.Samples.wValidBitsPerSample | 121 << ", wValidBitsPerSample: " << format.Samples.wValidBitsPerSample |
122 << ", dwChannelMask: 0x" << std::hex << format.dwChannelMask; | 122 << ", dwChannelMask: 0x" << std::hex << format.dwChannelMask; |
123 return os; | 123 return os; |
124 } | 124 } |
125 | 125 |
126 bool LoadAudiosesDll() { | 126 static bool LoadAudiosesDll() { |
127 static const wchar_t* const kAudiosesDLL = | 127 static const wchar_t* const kAudiosesDLL = |
128 L"%WINDIR%\\system32\\audioses.dll"; | 128 L"%WINDIR%\\system32\\audioses.dll"; |
129 | 129 |
130 wchar_t path[MAX_PATH] = {0}; | 130 wchar_t path[MAX_PATH] = {0}; |
131 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path)); | 131 ExpandEnvironmentStringsW(kAudiosesDLL, path, arraysize(path)); |
132 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL); | 132 return (LoadLibraryExW(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH) != NULL); |
133 } | 133 } |
134 | 134 |
135 bool CanCreateDeviceEnumerator() { | 135 static bool CanCreateDeviceEnumerator() { |
136 ScopedComPtr<IMMDeviceEnumerator> device_enumerator; | 136 ScopedComPtr<IMMDeviceEnumerator> device_enumerator; |
137 HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), | 137 HRESULT hr = device_enumerator.CreateInstance(__uuidof(MMDeviceEnumerator), |
138 NULL, CLSCTX_INPROC_SERVER); | 138 NULL, CLSCTX_INPROC_SERVER); |
139 | 139 |
140 // If we hit CO_E_NOTINITIALIZED, CoInitialize has not been called and it | 140 // If we hit CO_E_NOTINITIALIZED, CoInitialize has not been called and it |
141 // must be called at least once for each thread that uses the COM library. | 141 // must be called at least once for each thread that uses the COM library. |
142 CHECK_NE(hr, CO_E_NOTINITIALIZED); | 142 CHECK_NE(hr, CO_E_NOTINITIALIZED); |
143 | 143 |
144 return SUCCEEDED(hr); | 144 return SUCCEEDED(hr); |
145 } | 145 } |
146 | 146 |
| 147 static std::string GetDeviceID(IMMDevice* device) { |
| 148 ScopedCoMem<WCHAR> device_id_com; |
| 149 std::string device_id; |
| 150 if (SUCCEEDED(device->GetId(&device_id_com))) |
| 151 WideToUTF8(device_id_com, wcslen(device_id_com), &device_id); |
| 152 return device_id; |
| 153 } |
| 154 |
147 bool CoreAudioUtil::IsSupported() { | 155 bool CoreAudioUtil::IsSupported() { |
148 // It is possible to force usage of WaveXxx APIs by using a command line flag. | 156 // It is possible to force usage of WaveXxx APIs by using a command line flag. |
149 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); | 157 const CommandLine* cmd_line = CommandLine::ForCurrentProcess(); |
150 if (cmd_line->HasSwitch(switches::kForceWaveAudio)) { | 158 if (cmd_line->HasSwitch(switches::kForceWaveAudio)) { |
151 LOG(WARNING) << "Forcing usage of Windows WaveXxx APIs"; | 159 LOG(WARNING) << "Forcing usage of Windows WaveXxx APIs"; |
152 return false; | 160 return false; |
153 } | 161 } |
154 | 162 |
155 // Microsoft does not plan to make the Core Audio APIs available for use | 163 // Microsoft does not plan to make the Core Audio APIs available for use |
156 // with earlier versions of Windows, including Microsoft Windows Server 2003, | 164 // with earlier versions of Windows, including Microsoft Windows Server 2003, |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
256 hr = endpoint_device->GetState(&state); | 264 hr = endpoint_device->GetState(&state); |
257 if (SUCCEEDED(hr)) { | 265 if (SUCCEEDED(hr)) { |
258 if (!(state & DEVICE_STATE_ACTIVE)) { | 266 if (!(state & DEVICE_STATE_ACTIVE)) { |
259 DVLOG(1) << "Selected endpoint device is not active"; | 267 DVLOG(1) << "Selected endpoint device is not active"; |
260 endpoint_device.Release(); | 268 endpoint_device.Release(); |
261 } | 269 } |
262 } | 270 } |
263 return endpoint_device; | 271 return endpoint_device; |
264 } | 272 } |
265 | 273 |
| 274 std::string CoreAudioUtil::GetDefaultOutputDeviceID() { |
| 275 DCHECK(IsSupported()); |
| 276 ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole)); |
| 277 return device ? GetDeviceID(device) : std::string(); |
| 278 } |
| 279 |
266 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice( | 280 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice( |
267 const std::string& device_id) { | 281 const std::string& device_id) { |
268 DCHECK(IsSupported()); | 282 DCHECK(IsSupported()); |
269 ScopedComPtr<IMMDevice> endpoint_device; | 283 ScopedComPtr<IMMDevice> endpoint_device; |
270 | 284 |
271 // Create the IMMDeviceEnumerator interface. | 285 // Create the IMMDeviceEnumerator interface. |
272 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 286 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
273 CreateDeviceEnumerator(); | 287 CreateDeviceEnumerator(); |
274 if (!device_enumerator) | 288 if (!device_enumerator) |
275 return endpoint_device; | 289 return endpoint_device; |
276 | 290 |
277 // Retrieve an audio device specified by an endpoint device-identification | 291 // Retrieve an audio device specified by an endpoint device-identification |
278 // string. | 292 // string. |
279 HRESULT hr = device_enumerator->GetDevice(UTF8ToUTF16(device_id).c_str(), | 293 HRESULT hr = device_enumerator->GetDevice(UTF8ToUTF16(device_id).c_str(), |
280 endpoint_device.Receive()); | 294 endpoint_device.Receive()); |
281 DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: " | 295 DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: " |
282 << std::hex << hr; | 296 << std::hex << hr; |
283 return endpoint_device; | 297 return endpoint_device; |
284 } | 298 } |
285 | 299 |
286 HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) { | 300 HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) { |
287 DCHECK(IsSupported()); | 301 DCHECK(IsSupported()); |
288 | 302 |
289 // Retrieve unique name of endpoint device. | 303 // Retrieve unique name of endpoint device. |
290 // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}". | 304 // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}". |
291 AudioDeviceName device_name; | 305 AudioDeviceName device_name; |
292 ScopedCoMem<WCHAR> endpoint_device_id; | 306 device_name.unique_id = GetDeviceID(device); |
293 HRESULT hr = device->GetId(&endpoint_device_id); | 307 if (device_name.unique_id.empty()) |
294 if (FAILED(hr)) | 308 return E_FAIL; |
295 return hr; | |
296 WideToUTF8(endpoint_device_id, wcslen(endpoint_device_id), | |
297 &device_name.unique_id); | |
298 | 309 |
299 // Retrieve user-friendly name of endpoint device. | 310 // Retrieve user-friendly name of endpoint device. |
300 // Example: "Microphone (Realtek High Definition Audio)". | 311 // Example: "Microphone (Realtek High Definition Audio)". |
301 ScopedComPtr<IPropertyStore> properties; | 312 ScopedComPtr<IPropertyStore> properties; |
302 hr = device->OpenPropertyStore(STGM_READ, properties.Receive()); | 313 HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive()); |
303 if (FAILED(hr)) | 314 if (FAILED(hr)) |
304 return hr; | 315 return hr; |
305 base::win::ScopedPropVariant friendly_name; | 316 base::win::ScopedPropVariant friendly_name; |
306 hr = properties->GetValue(PKEY_Device_FriendlyName, friendly_name.Receive()); | 317 hr = properties->GetValue(PKEY_Device_FriendlyName, friendly_name.Receive()); |
307 if (FAILED(hr)) | 318 if (FAILED(hr)) |
308 return hr; | 319 return hr; |
309 if (friendly_name.get().vt == VT_LPWSTR && friendly_name.get().pwszVal) { | 320 if (friendly_name.get().vt == VT_LPWSTR && friendly_name.get().pwszVal) { |
310 WideToUTF8(friendly_name.get().pwszVal, | 321 WideToUTF8(friendly_name.get().pwszVal, |
311 wcslen(friendly_name.get().pwszVal), | 322 wcslen(friendly_name.get().pwszVal), |
312 &device_name.device_name); | 323 &device_name.device_name); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
390 ScopedComPtr<IMMDevice> output_device; | 401 ScopedComPtr<IMMDevice> output_device; |
391 for (UINT i = 0; i < count; ++i) { | 402 for (UINT i = 0; i < count; ++i) { |
392 collection->Item(i, output_device.Receive()); | 403 collection->Item(i, output_device.Receive()); |
393 std::string output_controller_id(CoreAudioUtil::GetAudioControllerID( | 404 std::string output_controller_id(CoreAudioUtil::GetAudioControllerID( |
394 output_device, enumerator)); | 405 output_device, enumerator)); |
395 if (output_controller_id == controller_id) | 406 if (output_controller_id == controller_id) |
396 break; | 407 break; |
397 output_device = NULL; | 408 output_device = NULL; |
398 } | 409 } |
399 | 410 |
400 std::string id; | 411 return output_device ? GetDeviceID(output_device) : std::string(); |
401 if (output_device) { | |
402 ScopedCoMem<WCHAR> wide_id; | |
403 output_device->GetId(&wide_id); | |
404 WideToUTF8(wide_id, wcslen(wide_id), &id); | |
405 } | |
406 | |
407 return id; | |
408 } | 412 } |
409 | 413 |
410 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) { | 414 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) { |
411 DCHECK(IsSupported()); | 415 DCHECK(IsSupported()); |
412 ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id); | 416 ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id); |
413 if (!audio_device) | 417 if (!audio_device) |
414 return std::string(); | 418 return std::string(); |
415 | 419 |
416 AudioDeviceName device_name; | 420 AudioDeviceName device_name; |
417 HRESULT hr = GetDeviceName(audio_device, &device_name); | 421 HRESULT hr = GetDeviceName(audio_device, &device_name); |
418 if (FAILED(hr)) | 422 if (FAILED(hr)) |
419 return std::string(); | 423 return std::string(); |
420 | 424 |
421 return device_name.device_name; | 425 return device_name.device_name; |
422 } | 426 } |
423 | 427 |
424 bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow, | 428 bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow, |
425 ERole role, | 429 ERole role, |
426 const std::string& device_id) { | 430 const std::string& device_id) { |
427 DCHECK(IsSupported()); | 431 DCHECK(IsSupported()); |
428 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); | 432 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); |
429 if (!device) | 433 if (!device) |
430 return false; | 434 return false; |
431 | 435 |
432 ScopedCoMem<WCHAR> default_device_id; | 436 std::string str_default(GetDeviceID(device)); |
433 HRESULT hr = device->GetId(&default_device_id); | 437 return device_id.compare(str_default) == 0; |
434 if (FAILED(hr)) | |
435 return false; | |
436 | |
437 std::string str_default; | |
438 WideToUTF8(default_device_id, wcslen(default_device_id), &str_default); | |
439 if (device_id.compare(str_default) != 0) | |
440 return false; | |
441 return true; | |
442 } | 438 } |
443 | 439 |
444 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { | 440 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { |
445 DCHECK(IsSupported()); | 441 DCHECK(IsSupported()); |
446 ScopedComPtr<IMMEndpoint> endpoint; | 442 ScopedComPtr<IMMEndpoint> endpoint; |
447 HRESULT hr = device->QueryInterface(endpoint.Receive()); | 443 HRESULT hr = device->QueryInterface(endpoint.Receive()); |
448 if (FAILED(hr)) { | 444 if (FAILED(hr)) { |
449 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; | 445 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; |
450 return eAll; | 446 return eAll; |
451 } | 447 } |
(...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
799 return false; | 795 return false; |
800 | 796 |
801 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to | 797 // Using the AUDCLNT_BUFFERFLAGS_SILENT flag eliminates the need to |
802 // explicitly write silence data to the rendering buffer. | 798 // explicitly write silence data to the rendering buffer. |
803 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; | 799 DVLOG(2) << "filling up " << num_frames_to_fill << " frames with silence"; |
804 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, | 800 return SUCCEEDED(render_client->ReleaseBuffer(num_frames_to_fill, |
805 AUDCLNT_BUFFERFLAGS_SILENT)); | 801 AUDCLNT_BUFFERFLAGS_SILENT)); |
806 } | 802 } |
807 | 803 |
808 } // namespace media | 804 } // namespace media |
OLD | NEW |