| 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 <devicetopology.h> | 7 #include <devicetopology.h> |
| 8 #include <dxdiag.h> | 8 #include <dxdiag.h> |
| 9 #include <functiondiscoverykeys_devpkey.h> | 9 #include <functiondiscoverykeys_devpkey.h> |
| 10 #include <objbase.h> | 10 #include <objbase.h> |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 148 static bool IsDeviceActive(IMMDevice* device) { | 148 static bool IsDeviceActive(IMMDevice* device) { |
| 149 DWORD state = DEVICE_STATE_DISABLED; | 149 DWORD state = DEVICE_STATE_DISABLED; |
| 150 return SUCCEEDED(device->GetState(&state)) && (state & DEVICE_STATE_ACTIVE); | 150 return SUCCEEDED(device->GetState(&state)) && (state & DEVICE_STATE_ACTIVE); |
| 151 } | 151 } |
| 152 | 152 |
| 153 static HRESULT GetDeviceFriendlyNameInternal(IMMDevice* device, | 153 static HRESULT GetDeviceFriendlyNameInternal(IMMDevice* device, |
| 154 std::string* friendly_name) { | 154 std::string* friendly_name) { |
| 155 // Retrieve user-friendly name of endpoint device. | 155 // Retrieve user-friendly name of endpoint device. |
| 156 // Example: "Microphone (Realtek High Definition Audio)". | 156 // Example: "Microphone (Realtek High Definition Audio)". |
| 157 ScopedComPtr<IPropertyStore> properties; | 157 ScopedComPtr<IPropertyStore> properties; |
| 158 HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.Receive()); | 158 HRESULT hr = device->OpenPropertyStore(STGM_READ, properties.GetAddressOf()); |
| 159 if (FAILED(hr)) | 159 if (FAILED(hr)) |
| 160 return hr; | 160 return hr; |
| 161 | 161 |
| 162 base::win::ScopedPropVariant friendly_name_pv; | 162 base::win::ScopedPropVariant friendly_name_pv; |
| 163 hr = properties->GetValue(PKEY_Device_FriendlyName, | 163 hr = properties->GetValue(PKEY_Device_FriendlyName, |
| 164 friendly_name_pv.Receive()); | 164 friendly_name_pv.Receive()); |
| 165 if (FAILED(hr)) | 165 if (FAILED(hr)) |
| 166 return hr; | 166 return hr; |
| 167 | 167 |
| 168 if (friendly_name_pv.get().vt == VT_LPWSTR && | 168 if (friendly_name_pv.get().vt == VT_LPWSTR && |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 254 // Create the IMMDeviceEnumerator interface. | 254 // Create the IMMDeviceEnumerator interface. |
| 255 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 255 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 256 CreateDeviceEnumerator(); | 256 CreateDeviceEnumerator(); |
| 257 if (!device_enumerator.Get()) | 257 if (!device_enumerator.Get()) |
| 258 return 0; | 258 return 0; |
| 259 | 259 |
| 260 // Generate a collection of active (present and not disabled) audio endpoint | 260 // Generate a collection of active (present and not disabled) audio endpoint |
| 261 // devices for the specified data-flow direction. | 261 // devices for the specified data-flow direction. |
| 262 // This method will succeed even if all devices are disabled. | 262 // This method will succeed even if all devices are disabled. |
| 263 ScopedComPtr<IMMDeviceCollection> collection; | 263 ScopedComPtr<IMMDeviceCollection> collection; |
| 264 HRESULT hr = device_enumerator->EnumAudioEndpoints(data_flow, | 264 HRESULT hr = device_enumerator->EnumAudioEndpoints( |
| 265 DEVICE_STATE_ACTIVE, | 265 data_flow, DEVICE_STATE_ACTIVE, collection.GetAddressOf()); |
| 266 collection.Receive()); | |
| 267 if (FAILED(hr)) { | 266 if (FAILED(hr)) { |
| 268 LOG(ERROR) << "IMMDeviceCollection::EnumAudioEndpoints: " << std::hex << hr; | 267 LOG(ERROR) << "IMMDeviceCollection::EnumAudioEndpoints: " << std::hex << hr; |
| 269 return 0; | 268 return 0; |
| 270 } | 269 } |
| 271 | 270 |
| 272 // Retrieve the number of active audio devices for the specified direction | 271 // Retrieve the number of active audio devices for the specified direction |
| 273 UINT number_of_active_devices = 0; | 272 UINT number_of_active_devices = 0; |
| 274 collection->GetCount(&number_of_active_devices); | 273 collection->GetCount(&number_of_active_devices); |
| 275 DVLOG(2) << ((data_flow == eCapture) ? "[in ] " : "[out] ") | 274 DVLOG(2) << ((data_flow == eCapture) ? "[in ] " : "[out] ") |
| 276 << "number of devices: " << number_of_active_devices; | 275 << "number of devices: " << number_of_active_devices; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 287 | 286 |
| 288 // Create the IMMDeviceEnumerator interface. | 287 // Create the IMMDeviceEnumerator interface. |
| 289 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 288 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 290 CreateDeviceEnumerator(); | 289 CreateDeviceEnumerator(); |
| 291 if (!device_enumerator.Get()) | 290 if (!device_enumerator.Get()) |
| 292 return endpoint_device; | 291 return endpoint_device; |
| 293 | 292 |
| 294 // Retrieve the default audio endpoint for the specified data-flow | 293 // Retrieve the default audio endpoint for the specified data-flow |
| 295 // direction and role. | 294 // direction and role. |
| 296 HRESULT hr = device_enumerator->GetDefaultAudioEndpoint( | 295 HRESULT hr = device_enumerator->GetDefaultAudioEndpoint( |
| 297 data_flow, role, endpoint_device.Receive()); | 296 data_flow, role, endpoint_device.GetAddressOf()); |
| 298 | 297 |
| 299 if (FAILED(hr)) { | 298 if (FAILED(hr)) { |
| 300 DVLOG(1) << "IMMDeviceEnumerator::GetDefaultAudioEndpoint: " | 299 DVLOG(1) << "IMMDeviceEnumerator::GetDefaultAudioEndpoint: " |
| 301 << std::hex << hr; | 300 << std::hex << hr; |
| 302 return endpoint_device; | 301 return endpoint_device; |
| 303 } | 302 } |
| 304 | 303 |
| 305 // Verify that the audio endpoint device is active, i.e., that the audio | 304 // Verify that the audio endpoint device is active, i.e., that the audio |
| 306 // adapter that connects to the endpoint device is present and enabled. | 305 // adapter that connects to the endpoint device is present and enabled. |
| 307 if (!IsDeviceActive(endpoint_device.Get())) { | 306 if (!IsDeviceActive(endpoint_device.Get())) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 322 | 321 |
| 323 // Create the IMMDeviceEnumerator interface. | 322 // Create the IMMDeviceEnumerator interface. |
| 324 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 323 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 325 CreateDeviceEnumerator(); | 324 CreateDeviceEnumerator(); |
| 326 if (!device_enumerator.Get()) | 325 if (!device_enumerator.Get()) |
| 327 return endpoint_device; | 326 return endpoint_device; |
| 328 | 327 |
| 329 // Retrieve an audio device specified by an endpoint device-identification | 328 // Retrieve an audio device specified by an endpoint device-identification |
| 330 // string. | 329 // string. |
| 331 HRESULT hr = device_enumerator->GetDevice( | 330 HRESULT hr = device_enumerator->GetDevice( |
| 332 base::UTF8ToUTF16(device_id).c_str(), endpoint_device.Receive()); | 331 base::UTF8ToUTF16(device_id).c_str(), endpoint_device.GetAddressOf()); |
| 333 DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: " | 332 DVLOG_IF(1, FAILED(hr)) << "IMMDeviceEnumerator::GetDevice: " |
| 334 << std::hex << hr; | 333 << std::hex << hr; |
| 335 | 334 |
| 336 if (FAILED(hr)) { | 335 if (FAILED(hr)) { |
| 337 DVLOG(1) << "IMMDeviceEnumerator::GetDevice: " << std::hex << hr; | 336 DVLOG(1) << "IMMDeviceEnumerator::GetDevice: " << std::hex << hr; |
| 338 return endpoint_device; | 337 return endpoint_device; |
| 339 } | 338 } |
| 340 | 339 |
| 341 // Verify that the audio endpoint device is active, i.e., that the audio | 340 // Verify that the audio endpoint device is active, i.e., that the audio |
| 342 // adapter that connects to the endpoint device is present and enabled. | 341 // adapter that connects to the endpoint device is present and enabled. |
| (...skipping 27 matching lines...) Expand all Loading... |
| 370 // Fetching the controller device id could be as simple as fetching the value | 369 // Fetching the controller device id could be as simple as fetching the value |
| 371 // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property | 370 // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property |
| 372 // store of the |device|, but that key isn't defined in any header and | 371 // store of the |device|, but that key isn't defined in any header and |
| 373 // according to MS should not be relied upon. | 372 // according to MS should not be relied upon. |
| 374 // So, instead, we go deeper, look at the device topology and fetch the | 373 // So, instead, we go deeper, look at the device topology and fetch the |
| 375 // PKEY_Device_InstanceId of the associated physical audio device. | 374 // PKEY_Device_InstanceId of the associated physical audio device. |
| 376 ScopedComPtr<IDeviceTopology> topology; | 375 ScopedComPtr<IDeviceTopology> topology; |
| 377 ScopedComPtr<IConnector> connector; | 376 ScopedComPtr<IConnector> connector; |
| 378 ScopedCoMem<WCHAR> filter_id; | 377 ScopedCoMem<WCHAR> filter_id; |
| 379 if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, | 378 if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, |
| 380 &topology)) || | 379 &topology)) || |
| 381 // For our purposes checking the first connected device should be enough | 380 // For our purposes checking the first connected device should be enough |
| 382 // and if there are cases where there are more than one device connected | 381 // and if there are cases where there are more than one device connected |
| 383 // we're not sure how to handle that anyway. So we pass 0. | 382 // we're not sure how to handle that anyway. So we pass 0. |
| 384 FAILED(topology->GetConnector(0, connector.Receive())) || | 383 FAILED(topology->GetConnector(0, connector.GetAddressOf())) || |
| 385 FAILED(connector->GetDeviceIdConnectedTo(&filter_id))) { | 384 FAILED(connector->GetDeviceIdConnectedTo(&filter_id))) { |
| 386 DLOG(ERROR) << "Failed to get the device identifier of the audio device"; | 385 DLOG(ERROR) << "Failed to get the device identifier of the audio device"; |
| 387 return std::string(); | 386 return std::string(); |
| 388 } | 387 } |
| 389 | 388 |
| 390 // Now look at the properties of the connected device node and fetch the | 389 // Now look at the properties of the connected device node and fetch the |
| 391 // instance id (PKEY_Device_InstanceId) of the device node that uniquely | 390 // instance id (PKEY_Device_InstanceId) of the device node that uniquely |
| 392 // identifies the controller. | 391 // identifies the controller. |
| 393 ScopedComPtr<IMMDevice> device_node; | 392 ScopedComPtr<IMMDevice> device_node; |
| 394 ScopedComPtr<IPropertyStore> properties; | 393 ScopedComPtr<IPropertyStore> properties; |
| 395 base::win::ScopedPropVariant instance_id; | 394 base::win::ScopedPropVariant instance_id; |
| 396 if (FAILED(enumerator->GetDevice(filter_id, device_node.Receive())) || | 395 if (FAILED(enumerator->GetDevice(filter_id, device_node.GetAddressOf())) || |
| 397 FAILED(device_node->OpenPropertyStore(STGM_READ, properties.Receive())) || | 396 FAILED(device_node->OpenPropertyStore(STGM_READ, |
| 397 properties.GetAddressOf())) || |
| 398 FAILED(properties->GetValue(PKEY_Device_InstanceId, | 398 FAILED(properties->GetValue(PKEY_Device_InstanceId, |
| 399 instance_id.Receive())) || | 399 instance_id.Receive())) || |
| 400 instance_id.get().vt != VT_LPWSTR) { | 400 instance_id.get().vt != VT_LPWSTR) { |
| 401 DLOG(ERROR) << "Failed to get instance id of the audio device node"; | 401 DLOG(ERROR) << "Failed to get instance id of the audio device node"; |
| 402 return std::string(); | 402 return std::string(); |
| 403 } | 403 } |
| 404 | 404 |
| 405 std::string controller_id; | 405 std::string controller_id; |
| 406 base::WideToUTF8(instance_id.get().pwszVal, | 406 base::WideToUTF8(instance_id.get().pwszVal, |
| 407 wcslen(instance_id.get().pwszVal), | 407 wcslen(instance_id.get().pwszVal), |
| (...skipping 30 matching lines...) Expand all Loading... |
| 438 ScopedComPtr<IMMDeviceEnumerator> enumerator(CreateDeviceEnumerator()); | 438 ScopedComPtr<IMMDeviceEnumerator> enumerator(CreateDeviceEnumerator()); |
| 439 std::string controller_id( | 439 std::string controller_id( |
| 440 GetAudioControllerID(input_device.Get(), enumerator.Get())); | 440 GetAudioControllerID(input_device.Get(), enumerator.Get())); |
| 441 if (controller_id.empty()) | 441 if (controller_id.empty()) |
| 442 return std::string(); | 442 return std::string(); |
| 443 | 443 |
| 444 // Now enumerate the available (and active) output devices and see if any of | 444 // Now enumerate the available (and active) output devices and see if any of |
| 445 // them is associated with the same controller. | 445 // them is associated with the same controller. |
| 446 ScopedComPtr<IMMDeviceCollection> collection; | 446 ScopedComPtr<IMMDeviceCollection> collection; |
| 447 enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, | 447 enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, |
| 448 collection.Receive()); | 448 collection.GetAddressOf()); |
| 449 if (!collection.Get()) | 449 if (!collection.Get()) |
| 450 return std::string(); | 450 return std::string(); |
| 451 | 451 |
| 452 UINT count = 0; | 452 UINT count = 0; |
| 453 collection->GetCount(&count); | 453 collection->GetCount(&count); |
| 454 ScopedComPtr<IMMDevice> output_device; | 454 ScopedComPtr<IMMDevice> output_device; |
| 455 for (UINT i = 0; i < count; ++i) { | 455 for (UINT i = 0; i < count; ++i) { |
| 456 collection->Item(i, output_device.Receive()); | 456 collection->Item(i, output_device.GetAddressOf()); |
| 457 std::string output_controller_id( | 457 std::string output_controller_id( |
| 458 GetAudioControllerID(output_device.Get(), enumerator.Get())); | 458 GetAudioControllerID(output_device.Get(), enumerator.Get())); |
| 459 if (output_controller_id == controller_id) | 459 if (output_controller_id == controller_id) |
| 460 break; | 460 break; |
| 461 output_device = NULL; | 461 output_device = NULL; |
| 462 } | 462 } |
| 463 | 463 |
| 464 return output_device.Get() ? GetDeviceID(output_device.Get()) : std::string(); | 464 return output_device.Get() ? GetDeviceID(output_device.Get()) : std::string(); |
| 465 } | 465 } |
| 466 | 466 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 483 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); | 483 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); |
| 484 if (!device.Get()) | 484 if (!device.Get()) |
| 485 return false; | 485 return false; |
| 486 | 486 |
| 487 std::string str_default(GetDeviceID(device.Get())); | 487 std::string str_default(GetDeviceID(device.Get())); |
| 488 return device_id.compare(str_default) == 0; | 488 return device_id.compare(str_default) == 0; |
| 489 } | 489 } |
| 490 | 490 |
| 491 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { | 491 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { |
| 492 ScopedComPtr<IMMEndpoint> endpoint; | 492 ScopedComPtr<IMMEndpoint> endpoint; |
| 493 HRESULT hr = device->QueryInterface(endpoint.Receive()); | 493 HRESULT hr = device->QueryInterface(endpoint.GetAddressOf()); |
| 494 if (FAILED(hr)) { | 494 if (FAILED(hr)) { |
| 495 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; | 495 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; |
| 496 return eAll; | 496 return eAll; |
| 497 } | 497 } |
| 498 | 498 |
| 499 EDataFlow data_flow; | 499 EDataFlow data_flow; |
| 500 hr = endpoint->GetDataFlow(&data_flow); | 500 hr = endpoint->GetDataFlow(&data_flow); |
| 501 if (FAILED(hr)) { | 501 if (FAILED(hr)) { |
| 502 DVLOG(1) << "IMMEndpoint::GetDataFlow: " << std::hex << hr; | 502 DVLOG(1) << "IMMEndpoint::GetDataFlow: " << std::hex << hr; |
| 503 return eAll; | 503 return eAll; |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 883 | 883 |
| 884 DXDIAG_INIT_PARAMS params = {sizeof(params)}; | 884 DXDIAG_INIT_PARAMS params = {sizeof(params)}; |
| 885 params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; | 885 params.dwDxDiagHeaderVersion = DXDIAG_DX9_SDK_VERSION; |
| 886 params.bAllowWHQLChecks = FALSE; | 886 params.bAllowWHQLChecks = FALSE; |
| 887 params.pReserved = NULL; | 887 params.pReserved = NULL; |
| 888 hr = provider->Initialize(¶ms); | 888 hr = provider->Initialize(¶ms); |
| 889 if (FAILED(hr)) | 889 if (FAILED(hr)) |
| 890 return false; | 890 return false; |
| 891 | 891 |
| 892 ScopedComPtr<IDxDiagContainer, &IID_IDxDiagContainer> root; | 892 ScopedComPtr<IDxDiagContainer, &IID_IDxDiagContainer> root; |
| 893 hr = provider->GetRootContainer(root.Receive()); | 893 hr = provider->GetRootContainer(root.GetAddressOf()); |
| 894 if (FAILED(hr)) | 894 if (FAILED(hr)) |
| 895 return false; | 895 return false; |
| 896 | 896 |
| 897 // Limit to the SoundDevices subtree. The tree in its entirity is | 897 // Limit to the SoundDevices subtree. The tree in its entirity is |
| 898 // enormous and only this branch contains useful information. | 898 // enormous and only this branch contains useful information. |
| 899 ScopedComPtr<IDxDiagContainer, &IID_IDxDiagContainer> sound_devices; | 899 ScopedComPtr<IDxDiagContainer, &IID_IDxDiagContainer> sound_devices; |
| 900 hr = root->GetChildContainer(L"DxDiag_DirectSound.DxDiag_SoundDevices.0", | 900 hr = root->GetChildContainer(L"DxDiag_DirectSound.DxDiag_SoundDevices.0", |
| 901 sound_devices.Receive()); | 901 sound_devices.GetAddressOf()); |
| 902 if (FAILED(hr)) | 902 if (FAILED(hr)) |
| 903 return false; | 903 return false; |
| 904 | 904 |
| 905 base::win::ScopedVariant variant; | 905 base::win::ScopedVariant variant; |
| 906 hr = sound_devices->GetProp(L"szDriverName", variant.Receive()); | 906 hr = sound_devices->GetProp(L"szDriverName", variant.Receive()); |
| 907 if (FAILED(hr)) | 907 if (FAILED(hr)) |
| 908 return false; | 908 return false; |
| 909 | 909 |
| 910 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { | 910 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { |
| 911 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), | 911 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), |
| 912 driver_name); | 912 driver_name); |
| 913 } | 913 } |
| 914 | 914 |
| 915 variant.Reset(); | 915 variant.Reset(); |
| 916 hr = sound_devices->GetProp(L"szDriverVersion", variant.Receive()); | 916 hr = sound_devices->GetProp(L"szDriverVersion", variant.Receive()); |
| 917 if (FAILED(hr)) | 917 if (FAILED(hr)) |
| 918 return false; | 918 return false; |
| 919 | 919 |
| 920 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { | 920 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { |
| 921 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), | 921 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), |
| 922 driver_version); | 922 driver_version); |
| 923 } | 923 } |
| 924 | 924 |
| 925 return true; | 925 return true; |
| 926 } | 926 } |
| 927 | 927 |
| 928 } // namespace media | 928 } // namespace media |
| OLD | NEW |