| 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 |