| 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 <stddef.h> | 10 #include <stddef.h> |
| (...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 252 } | 252 } |
| 253 | 253 |
| 254 AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() { | 254 AUDCLNT_SHAREMODE CoreAudioUtil::GetShareMode() { |
| 255 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); | 255 const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); |
| 256 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) | 256 if (cmd_line->HasSwitch(switches::kEnableExclusiveAudio)) |
| 257 return AUDCLNT_SHAREMODE_EXCLUSIVE; | 257 return AUDCLNT_SHAREMODE_EXCLUSIVE; |
| 258 return AUDCLNT_SHAREMODE_SHARED; | 258 return AUDCLNT_SHAREMODE_SHARED; |
| 259 } | 259 } |
| 260 | 260 |
| 261 int CoreAudioUtil::NumberOfActiveDevices(EDataFlow data_flow) { | 261 int CoreAudioUtil::NumberOfActiveDevices(EDataFlow data_flow) { |
| 262 DCHECK(IsSupported()); | |
| 263 // Create the IMMDeviceEnumerator interface. | 262 // Create the IMMDeviceEnumerator interface. |
| 264 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 263 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 265 CreateDeviceEnumerator(); | 264 CreateDeviceEnumerator(); |
| 266 if (!device_enumerator.get()) | 265 if (!device_enumerator.get()) |
| 267 return 0; | 266 return 0; |
| 268 | 267 |
| 269 // Generate a collection of active (present and not disabled) audio endpoint | 268 // Generate a collection of active (present and not disabled) audio endpoint |
| 270 // devices for the specified data-flow direction. | 269 // devices for the specified data-flow direction. |
| 271 // This method will succeed even if all devices are disabled. | 270 // This method will succeed even if all devices are disabled. |
| 272 ScopedComPtr<IMMDeviceCollection> collection; | 271 ScopedComPtr<IMMDeviceCollection> collection; |
| 273 HRESULT hr = device_enumerator->EnumAudioEndpoints(data_flow, | 272 HRESULT hr = device_enumerator->EnumAudioEndpoints(data_flow, |
| 274 DEVICE_STATE_ACTIVE, | 273 DEVICE_STATE_ACTIVE, |
| 275 collection.Receive()); | 274 collection.Receive()); |
| 276 if (FAILED(hr)) { | 275 if (FAILED(hr)) { |
| 277 LOG(ERROR) << "IMMDeviceCollection::EnumAudioEndpoints: " << std::hex << hr; | 276 LOG(ERROR) << "IMMDeviceCollection::EnumAudioEndpoints: " << std::hex << hr; |
| 278 return 0; | 277 return 0; |
| 279 } | 278 } |
| 280 | 279 |
| 281 // Retrieve the number of active audio devices for the specified direction | 280 // Retrieve the number of active audio devices for the specified direction |
| 282 UINT number_of_active_devices = 0; | 281 UINT number_of_active_devices = 0; |
| 283 collection->GetCount(&number_of_active_devices); | 282 collection->GetCount(&number_of_active_devices); |
| 284 DVLOG(2) << ((data_flow == eCapture) ? "[in ] " : "[out] ") | 283 DVLOG(2) << ((data_flow == eCapture) ? "[in ] " : "[out] ") |
| 285 << "number of devices: " << number_of_active_devices; | 284 << "number of devices: " << number_of_active_devices; |
| 286 return static_cast<int>(number_of_active_devices); | 285 return static_cast<int>(number_of_active_devices); |
| 287 } | 286 } |
| 288 | 287 |
| 289 ScopedComPtr<IMMDeviceEnumerator> CoreAudioUtil::CreateDeviceEnumerator() { | 288 ScopedComPtr<IMMDeviceEnumerator> CoreAudioUtil::CreateDeviceEnumerator() { |
| 290 DCHECK(IsSupported()); | 289 return CreateDeviceEnumeratorInternal(true); |
| 291 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | |
| 292 CreateDeviceEnumeratorInternal(true); | |
| 293 CHECK(device_enumerator); | |
| 294 return device_enumerator; | |
| 295 } | 290 } |
| 296 | 291 |
| 297 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow, | 292 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDefaultDevice(EDataFlow data_flow, |
| 298 ERole role) { | 293 ERole role) { |
| 299 DCHECK(IsSupported()); | |
| 300 ScopedComPtr<IMMDevice> endpoint_device; | 294 ScopedComPtr<IMMDevice> endpoint_device; |
| 301 | 295 |
| 302 // Create the IMMDeviceEnumerator interface. | 296 // Create the IMMDeviceEnumerator interface. |
| 303 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 297 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 304 CreateDeviceEnumerator(); | 298 CreateDeviceEnumerator(); |
| 305 if (!device_enumerator.get()) | 299 if (!device_enumerator.get()) |
| 306 return endpoint_device; | 300 return endpoint_device; |
| 307 | 301 |
| 308 // Retrieve the default audio endpoint for the specified data-flow | 302 // Retrieve the default audio endpoint for the specified data-flow |
| 309 // direction and role. | 303 // direction and role. |
| 310 HRESULT hr = device_enumerator->GetDefaultAudioEndpoint( | 304 HRESULT hr = device_enumerator->GetDefaultAudioEndpoint( |
| 311 data_flow, role, endpoint_device.Receive()); | 305 data_flow, role, endpoint_device.Receive()); |
| 312 | 306 |
| 313 if (FAILED(hr)) { | 307 if (FAILED(hr)) { |
| 314 DVLOG(1) << "IMMDeviceEnumerator::GetDefaultAudioEndpoint: " | 308 DVLOG(1) << "IMMDeviceEnumerator::GetDefaultAudioEndpoint: " |
| 315 << std::hex << hr; | 309 << std::hex << hr; |
| 316 return endpoint_device; | 310 return endpoint_device; |
| 317 } | 311 } |
| 318 | 312 |
| 319 // Verify that the audio endpoint device is active, i.e., that the audio | 313 // Verify that the audio endpoint device is active, i.e., that the audio |
| 320 // adapter that connects to the endpoint device is present and enabled. | 314 // adapter that connects to the endpoint device is present and enabled. |
| 321 if (!IsDeviceActive(endpoint_device.get())) { | 315 if (!IsDeviceActive(endpoint_device.get())) { |
| 322 DVLOG(1) << "Selected endpoint device is not active"; | 316 DVLOG(1) << "Selected endpoint device is not active"; |
| 323 endpoint_device.Release(); | 317 endpoint_device.Release(); |
| 324 } | 318 } |
| 325 return endpoint_device; | 319 return endpoint_device; |
| 326 } | 320 } |
| 327 | 321 |
| 328 std::string CoreAudioUtil::GetDefaultOutputDeviceID() { | 322 std::string CoreAudioUtil::GetDefaultOutputDeviceID() { |
| 329 DCHECK(IsSupported()); | |
| 330 ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole)); | 323 ScopedComPtr<IMMDevice> device(CreateDefaultDevice(eRender, eConsole)); |
| 331 return device.get() ? GetDeviceID(device.get()) : std::string(); | 324 return device.get() ? GetDeviceID(device.get()) : std::string(); |
| 332 } | 325 } |
| 333 | 326 |
| 334 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice( | 327 ScopedComPtr<IMMDevice> CoreAudioUtil::CreateDevice( |
| 335 const std::string& device_id) { | 328 const std::string& device_id) { |
| 336 DCHECK(IsSupported()); | |
| 337 ScopedComPtr<IMMDevice> endpoint_device; | 329 ScopedComPtr<IMMDevice> endpoint_device; |
| 338 | 330 |
| 339 // Create the IMMDeviceEnumerator interface. | 331 // Create the IMMDeviceEnumerator interface. |
| 340 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = | 332 ScopedComPtr<IMMDeviceEnumerator> device_enumerator = |
| 341 CreateDeviceEnumerator(); | 333 CreateDeviceEnumerator(); |
| 342 if (!device_enumerator.get()) | 334 if (!device_enumerator.get()) |
| 343 return endpoint_device; | 335 return endpoint_device; |
| 344 | 336 |
| 345 // Retrieve an audio device specified by an endpoint device-identification | 337 // Retrieve an audio device specified by an endpoint device-identification |
| 346 // string. | 338 // string. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 357 // Verify that the audio endpoint device is active, i.e., that the audio | 349 // Verify that the audio endpoint device is active, i.e., that the audio |
| 358 // adapter that connects to the endpoint device is present and enabled. | 350 // adapter that connects to the endpoint device is present and enabled. |
| 359 if (!IsDeviceActive(endpoint_device.get())) { | 351 if (!IsDeviceActive(endpoint_device.get())) { |
| 360 DVLOG(1) << "Selected endpoint device is not active"; | 352 DVLOG(1) << "Selected endpoint device is not active"; |
| 361 endpoint_device.Release(); | 353 endpoint_device.Release(); |
| 362 } | 354 } |
| 363 return endpoint_device; | 355 return endpoint_device; |
| 364 } | 356 } |
| 365 | 357 |
| 366 HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) { | 358 HRESULT CoreAudioUtil::GetDeviceName(IMMDevice* device, AudioDeviceName* name) { |
| 367 DCHECK(IsSupported()); | |
| 368 | |
| 369 // Retrieve unique name of endpoint device. | 359 // Retrieve unique name of endpoint device. |
| 370 // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}". | 360 // Example: "{0.0.1.00000000}.{8db6020f-18e3-4f25-b6f5-7726c9122574}". |
| 371 AudioDeviceName device_name; | 361 AudioDeviceName device_name; |
| 372 device_name.unique_id = GetDeviceID(device); | 362 device_name.unique_id = GetDeviceID(device); |
| 373 if (device_name.unique_id.empty()) | 363 if (device_name.unique_id.empty()) |
| 374 return E_FAIL; | 364 return E_FAIL; |
| 375 | 365 |
| 376 HRESULT hr = GetDeviceFriendlyNameInternal(device, &device_name.device_name); | 366 HRESULT hr = GetDeviceFriendlyNameInternal(device, &device_name.device_name); |
| 377 if (FAILED(hr)) | 367 if (FAILED(hr)) |
| 378 return hr; | 368 return hr; |
| 379 | 369 |
| 380 *name = device_name; | 370 *name = device_name; |
| 381 DVLOG(2) << "friendly name: " << device_name.device_name; | 371 DVLOG(2) << "friendly name: " << device_name.device_name; |
| 382 DVLOG(2) << "unique id : " << device_name.unique_id; | 372 DVLOG(2) << "unique id : " << device_name.unique_id; |
| 383 return hr; | 373 return hr; |
| 384 } | 374 } |
| 385 | 375 |
| 386 std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device, | 376 std::string CoreAudioUtil::GetAudioControllerID(IMMDevice* device, |
| 387 IMMDeviceEnumerator* enumerator) { | 377 IMMDeviceEnumerator* enumerator) { |
| 388 DCHECK(IsSupported()); | |
| 389 | |
| 390 // Fetching the controller device id could be as simple as fetching the value | 378 // Fetching the controller device id could be as simple as fetching the value |
| 391 // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property | 379 // of the "{B3F8FA53-0004-438E-9003-51A46E139BFC},2" property in the property |
| 392 // store of the |device|, but that key isn't defined in any header and | 380 // store of the |device|, but that key isn't defined in any header and |
| 393 // according to MS should not be relied upon. | 381 // according to MS should not be relied upon. |
| 394 // So, instead, we go deeper, look at the device topology and fetch the | 382 // So, instead, we go deeper, look at the device topology and fetch the |
| 395 // PKEY_Device_InstanceId of the associated physical audio device. | 383 // PKEY_Device_InstanceId of the associated physical audio device. |
| 396 ScopedComPtr<IDeviceTopology> topology; | 384 ScopedComPtr<IDeviceTopology> topology; |
| 397 ScopedComPtr<IConnector> connector; | 385 ScopedComPtr<IConnector> connector; |
| 398 ScopedCoMem<WCHAR> filter_id; | 386 ScopedCoMem<WCHAR> filter_id; |
| 399 if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, | 387 if (FAILED(device->Activate(__uuidof(IDeviceTopology), CLSCTX_ALL, NULL, |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 478 GetAudioControllerID(output_device.get(), enumerator.get())); | 466 GetAudioControllerID(output_device.get(), enumerator.get())); |
| 479 if (output_controller_id == controller_id) | 467 if (output_controller_id == controller_id) |
| 480 break; | 468 break; |
| 481 output_device = NULL; | 469 output_device = NULL; |
| 482 } | 470 } |
| 483 | 471 |
| 484 return output_device.get() ? GetDeviceID(output_device.get()) : std::string(); | 472 return output_device.get() ? GetDeviceID(output_device.get()) : std::string(); |
| 485 } | 473 } |
| 486 | 474 |
| 487 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) { | 475 std::string CoreAudioUtil::GetFriendlyName(const std::string& device_id) { |
| 488 DCHECK(IsSupported()); | |
| 489 ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id); | 476 ScopedComPtr<IMMDevice> audio_device = CreateDevice(device_id); |
| 490 if (!audio_device.get()) | 477 if (!audio_device.get()) |
| 491 return std::string(); | 478 return std::string(); |
| 492 | 479 |
| 493 AudioDeviceName device_name; | 480 AudioDeviceName device_name; |
| 494 HRESULT hr = GetDeviceName(audio_device.get(), &device_name); | 481 HRESULT hr = GetDeviceName(audio_device.get(), &device_name); |
| 495 if (FAILED(hr)) | 482 if (FAILED(hr)) |
| 496 return std::string(); | 483 return std::string(); |
| 497 | 484 |
| 498 return device_name.device_name; | 485 return device_name.device_name; |
| 499 } | 486 } |
| 500 | 487 |
| 501 bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow, | 488 bool CoreAudioUtil::DeviceIsDefault(EDataFlow flow, |
| 502 ERole role, | 489 ERole role, |
| 503 const std::string& device_id) { | 490 const std::string& device_id) { |
| 504 DCHECK(IsSupported()); | |
| 505 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); | 491 ScopedComPtr<IMMDevice> device = CreateDefaultDevice(flow, role); |
| 506 if (!device.get()) | 492 if (!device.get()) |
| 507 return false; | 493 return false; |
| 508 | 494 |
| 509 std::string str_default(GetDeviceID(device.get())); | 495 std::string str_default(GetDeviceID(device.get())); |
| 510 return device_id.compare(str_default) == 0; | 496 return device_id.compare(str_default) == 0; |
| 511 } | 497 } |
| 512 | 498 |
| 513 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { | 499 EDataFlow CoreAudioUtil::GetDataFlow(IMMDevice* device) { |
| 514 DCHECK(IsSupported()); | |
| 515 ScopedComPtr<IMMEndpoint> endpoint; | 500 ScopedComPtr<IMMEndpoint> endpoint; |
| 516 HRESULT hr = device->QueryInterface(endpoint.Receive()); | 501 HRESULT hr = device->QueryInterface(endpoint.Receive()); |
| 517 if (FAILED(hr)) { | 502 if (FAILED(hr)) { |
| 518 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; | 503 DVLOG(1) << "IMMDevice::QueryInterface: " << std::hex << hr; |
| 519 return eAll; | 504 return eAll; |
| 520 } | 505 } |
| 521 | 506 |
| 522 EDataFlow data_flow; | 507 EDataFlow data_flow; |
| 523 hr = endpoint->GetDataFlow(&data_flow); | 508 hr = endpoint->GetDataFlow(&data_flow); |
| 524 if (FAILED(hr)) { | 509 if (FAILED(hr)) { |
| 525 DVLOG(1) << "IMMEndpoint::GetDataFlow: " << std::hex << hr; | 510 DVLOG(1) << "IMMEndpoint::GetDataFlow: " << std::hex << hr; |
| 526 return eAll; | 511 return eAll; |
| 527 } | 512 } |
| 528 return data_flow; | 513 return data_flow; |
| 529 } | 514 } |
| 530 | 515 |
| 531 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient( | 516 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient( |
| 532 IMMDevice* audio_device) { | 517 IMMDevice* audio_device) { |
| 533 DCHECK(IsSupported()); | |
| 534 | |
| 535 // Creates and activates an IAudioClient COM object given the selected | 518 // Creates and activates an IAudioClient COM object given the selected |
| 536 // endpoint device. | 519 // endpoint device. |
| 537 ScopedComPtr<IAudioClient> audio_client; | 520 ScopedComPtr<IAudioClient> audio_client; |
| 538 HRESULT hr = audio_device->Activate(__uuidof(IAudioClient), | 521 HRESULT hr = audio_device->Activate(__uuidof(IAudioClient), |
| 539 CLSCTX_INPROC_SERVER, | 522 CLSCTX_INPROC_SERVER, |
| 540 NULL, | 523 NULL, |
| 541 audio_client.ReceiveVoid()); | 524 audio_client.ReceiveVoid()); |
| 542 DVLOG_IF(1, FAILED(hr)) << "IMMDevice::Activate: " << std::hex << hr; | 525 DVLOG_IF(1, FAILED(hr)) << "IMMDevice::Activate: " << std::hex << hr; |
| 543 return audio_client; | 526 return audio_client; |
| 544 } | 527 } |
| 545 | 528 |
| 546 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateDefaultClient( | 529 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateDefaultClient( |
| 547 EDataFlow data_flow, ERole role) { | 530 EDataFlow data_flow, ERole role) { |
| 548 DCHECK(IsSupported()); | |
| 549 ScopedComPtr<IMMDevice> default_device(CreateDefaultDevice(data_flow, role)); | 531 ScopedComPtr<IMMDevice> default_device(CreateDefaultDevice(data_flow, role)); |
| 550 return (default_device.get() ? CreateClient(default_device.get()) | 532 return (default_device.get() ? CreateClient(default_device.get()) |
| 551 : ScopedComPtr<IAudioClient>()); | 533 : ScopedComPtr<IAudioClient>()); |
| 552 } | 534 } |
| 553 | 535 |
| 554 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient( | 536 ScopedComPtr<IAudioClient> CoreAudioUtil::CreateClient( |
| 555 const std::string& device_id, EDataFlow data_flow, ERole role) { | 537 const std::string& device_id, EDataFlow data_flow, ERole role) { |
| 556 if (IsDefaultDeviceId(device_id)) | 538 if (IsDefaultDeviceId(device_id)) |
| 557 return CreateDefaultClient(data_flow, role); | 539 return CreateDefaultClient(data_flow, role); |
| 558 | 540 |
| 559 ScopedComPtr<IMMDevice> device(CreateDevice(device_id)); | 541 ScopedComPtr<IMMDevice> device(CreateDevice(device_id)); |
| 560 if (!device.get()) | 542 if (!device.get()) |
| 561 return ScopedComPtr<IAudioClient>(); | 543 return ScopedComPtr<IAudioClient>(); |
| 562 | 544 |
| 563 return CreateClient(device.get()); | 545 return CreateClient(device.get()); |
| 564 } | 546 } |
| 565 | 547 |
| 566 HRESULT CoreAudioUtil::GetSharedModeMixFormat( | 548 HRESULT CoreAudioUtil::GetSharedModeMixFormat( |
| 567 IAudioClient* client, WAVEFORMATPCMEX* format) { | 549 IAudioClient* client, WAVEFORMATPCMEX* format) { |
| 568 DCHECK(IsSupported()); | |
| 569 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex; | 550 ScopedCoMem<WAVEFORMATPCMEX> format_pcmex; |
| 570 HRESULT hr = client->GetMixFormat( | 551 HRESULT hr = client->GetMixFormat( |
| 571 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex)); | 552 reinterpret_cast<WAVEFORMATEX**>(&format_pcmex)); |
| 572 if (FAILED(hr)) | 553 if (FAILED(hr)) |
| 573 return hr; | 554 return hr; |
| 574 | 555 |
| 575 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize; | 556 size_t bytes = sizeof(WAVEFORMATEX) + format_pcmex->Format.cbSize; |
| 576 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX)); | 557 DCHECK_EQ(bytes, sizeof(WAVEFORMATPCMEX)); |
| 577 | 558 |
| 578 memcpy(format, format_pcmex, bytes); | 559 memcpy(format, format_pcmex, bytes); |
| 579 DVLOG(2) << *format; | 560 DVLOG(2) << *format; |
| 580 | 561 |
| 581 return hr; | 562 return hr; |
| 582 } | 563 } |
| 583 | 564 |
| 584 bool CoreAudioUtil::IsFormatSupported(IAudioClient* client, | 565 bool CoreAudioUtil::IsFormatSupported(IAudioClient* client, |
| 585 AUDCLNT_SHAREMODE share_mode, | 566 AUDCLNT_SHAREMODE share_mode, |
| 586 const WAVEFORMATPCMEX* format) { | 567 const WAVEFORMATPCMEX* format) { |
| 587 DCHECK(IsSupported()); | |
| 588 ScopedCoMem<WAVEFORMATEXTENSIBLE> closest_match; | 568 ScopedCoMem<WAVEFORMATEXTENSIBLE> closest_match; |
| 589 HRESULT hr = client->IsFormatSupported( | 569 HRESULT hr = client->IsFormatSupported( |
| 590 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format), | 570 share_mode, reinterpret_cast<const WAVEFORMATEX*>(format), |
| 591 reinterpret_cast<WAVEFORMATEX**>(&closest_match)); | 571 reinterpret_cast<WAVEFORMATEX**>(&closest_match)); |
| 592 | 572 |
| 593 // This log can only be triggered for shared mode. | 573 // This log can only be triggered for shared mode. |
| 594 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " | 574 DLOG_IF(ERROR, hr == S_FALSE) << "Format is not supported " |
| 595 << "but a closest match exists."; | 575 << "but a closest match exists."; |
| 596 // This log can be triggered both for shared and exclusive modes. | 576 // This log can be triggered both for shared and exclusive modes. |
| 597 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format."; | 577 DLOG_IF(ERROR, hr == AUDCLNT_E_UNSUPPORTED_FORMAT) << "Unsupported format."; |
| 598 if (hr == S_FALSE) { | 578 if (hr == S_FALSE) { |
| 599 DVLOG(2) << *closest_match; | 579 DVLOG(2) << *closest_match; |
| 600 } | 580 } |
| 601 | 581 |
| 602 return (hr == S_OK); | 582 return (hr == S_OK); |
| 603 } | 583 } |
| 604 | 584 |
| 605 bool CoreAudioUtil::IsChannelLayoutSupported(const std::string& device_id, | 585 bool CoreAudioUtil::IsChannelLayoutSupported(const std::string& device_id, |
| 606 EDataFlow data_flow, | 586 EDataFlow data_flow, |
| 607 ERole role, | 587 ERole role, |
| 608 ChannelLayout channel_layout) { | 588 ChannelLayout channel_layout) { |
| 609 DCHECK(IsSupported()); | |
| 610 | |
| 611 // First, get the preferred mixing format for shared mode streams. | 589 // First, get the preferred mixing format for shared mode streams. |
| 612 | |
| 613 ScopedComPtr<IAudioClient> client(CreateClient(device_id, data_flow, role)); | 590 ScopedComPtr<IAudioClient> client(CreateClient(device_id, data_flow, role)); |
| 614 if (!client.get()) | 591 if (!client.get()) |
| 615 return false; | 592 return false; |
| 616 | 593 |
| 617 WAVEFORMATPCMEX format; | 594 WAVEFORMATPCMEX format; |
| 618 HRESULT hr = GetSharedModeMixFormat(client.get(), &format); | 595 HRESULT hr = GetSharedModeMixFormat(client.get(), &format); |
| 619 if (FAILED(hr)) | 596 if (FAILED(hr)) |
| 620 return false; | 597 return false; |
| 621 | 598 |
| 622 // Next, check if it is possible to use an alternative format where the | 599 // Next, check if it is possible to use an alternative format where the |
| (...skipping 25 matching lines...) Expand all Loading... |
| 648 // an even wider range of shared-mode formats where the installation package | 625 // an even wider range of shared-mode formats where the installation package |
| 649 // for the audio device includes a local effects (LFX) audio processing | 626 // for the audio device includes a local effects (LFX) audio processing |
| 650 // object (APO) that can handle format conversions. | 627 // object (APO) that can handle format conversions. |
| 651 return CoreAudioUtil::IsFormatSupported(client.get(), | 628 return CoreAudioUtil::IsFormatSupported(client.get(), |
| 652 AUDCLNT_SHAREMODE_SHARED, &format); | 629 AUDCLNT_SHAREMODE_SHARED, &format); |
| 653 } | 630 } |
| 654 | 631 |
| 655 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client, | 632 HRESULT CoreAudioUtil::GetDevicePeriod(IAudioClient* client, |
| 656 AUDCLNT_SHAREMODE share_mode, | 633 AUDCLNT_SHAREMODE share_mode, |
| 657 REFERENCE_TIME* device_period) { | 634 REFERENCE_TIME* device_period) { |
| 658 DCHECK(IsSupported()); | |
| 659 | |
| 660 // Get the period of the engine thread. | 635 // Get the period of the engine thread. |
| 661 REFERENCE_TIME default_period = 0; | 636 REFERENCE_TIME default_period = 0; |
| 662 REFERENCE_TIME minimum_period = 0; | 637 REFERENCE_TIME minimum_period = 0; |
| 663 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period); | 638 HRESULT hr = client->GetDevicePeriod(&default_period, &minimum_period); |
| 664 if (FAILED(hr)) | 639 if (FAILED(hr)) |
| 665 return hr; | 640 return hr; |
| 666 | 641 |
| 667 *device_period = (share_mode == AUDCLNT_SHAREMODE_SHARED) ? default_period : | 642 *device_period = (share_mode == AUDCLNT_SHAREMODE_SHARED) ? default_period : |
| 668 minimum_period; | 643 minimum_period; |
| 669 DVLOG(2) << "device_period: " | 644 DVLOG(2) << "device_period: " |
| 670 << RefererenceTimeToTimeDelta(*device_period).InMillisecondsF() | 645 << RefererenceTimeToTimeDelta(*device_period).InMillisecondsF() |
| 671 << " [ms]"; | 646 << " [ms]"; |
| 672 return hr; | 647 return hr; |
| 673 } | 648 } |
| 674 | 649 |
| 675 HRESULT CoreAudioUtil::GetPreferredAudioParameters( | 650 HRESULT CoreAudioUtil::GetPreferredAudioParameters( |
| 676 IAudioClient* client, AudioParameters* params) { | 651 IAudioClient* client, AudioParameters* params) { |
| 677 DCHECK(IsSupported()); | |
| 678 WAVEFORMATPCMEX mix_format; | 652 WAVEFORMATPCMEX mix_format; |
| 679 HRESULT hr = GetSharedModeMixFormat(client, &mix_format); | 653 HRESULT hr = GetSharedModeMixFormat(client, &mix_format); |
| 680 if (FAILED(hr)) | 654 if (FAILED(hr)) |
| 681 return hr; | 655 return hr; |
| 682 | 656 |
| 683 REFERENCE_TIME default_period = 0; | 657 REFERENCE_TIME default_period = 0; |
| 684 hr = GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED, &default_period); | 658 hr = GetDevicePeriod(client, AUDCLNT_SHAREMODE_SHARED, &default_period); |
| 685 if (FAILED(hr)) | 659 if (FAILED(hr)) |
| 686 return hr; | 660 return hr; |
| 687 | 661 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 734 bits_per_sample, | 708 bits_per_sample, |
| 735 frames_per_buffer); | 709 frames_per_buffer); |
| 736 | 710 |
| 737 *params = audio_params; | 711 *params = audio_params; |
| 738 return hr; | 712 return hr; |
| 739 } | 713 } |
| 740 | 714 |
| 741 HRESULT CoreAudioUtil::GetPreferredAudioParameters(const std::string& device_id, | 715 HRESULT CoreAudioUtil::GetPreferredAudioParameters(const std::string& device_id, |
| 742 bool is_output_device, | 716 bool is_output_device, |
| 743 AudioParameters* params) { | 717 AudioParameters* params) { |
| 744 DCHECK(IsSupported()); | |
| 745 | |
| 746 ScopedComPtr<IMMDevice> device; | 718 ScopedComPtr<IMMDevice> device; |
| 747 if (device_id == AudioDeviceDescription::kDefaultDeviceId) { | 719 if (device_id == AudioDeviceDescription::kDefaultDeviceId) { |
| 748 device = CoreAudioUtil::CreateDefaultDevice( | 720 device = CoreAudioUtil::CreateDefaultDevice( |
| 749 is_output_device ? eRender : eCapture, eConsole); | 721 is_output_device ? eRender : eCapture, eConsole); |
| 750 } else if (device_id == AudioDeviceDescription::kLoopbackInputDeviceId || | 722 } else if (device_id == AudioDeviceDescription::kLoopbackInputDeviceId || |
| 751 device_id == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { | 723 device_id == AudioDeviceDescription::kLoopbackWithMuteDeviceId) { |
| 752 DCHECK(!is_output_device); | 724 DCHECK(!is_output_device); |
| 753 device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole); | 725 device = CoreAudioUtil::CreateDefaultDevice(eRender, eConsole); |
| 754 } else if (device_id == AudioDeviceDescription::kCommunicationsDeviceId) { | 726 } else if (device_id == AudioDeviceDescription::kCommunicationsDeviceId) { |
| 755 device = CoreAudioUtil::CreateDefaultDevice( | 727 device = CoreAudioUtil::CreateDefaultDevice( |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 return 0; | 771 return 0; |
| 800 | 772 |
| 801 return static_cast<ChannelConfig>(format.dwChannelMask); | 773 return static_cast<ChannelConfig>(format.dwChannelMask); |
| 802 } | 774 } |
| 803 | 775 |
| 804 HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client, | 776 HRESULT CoreAudioUtil::SharedModeInitialize(IAudioClient* client, |
| 805 const WAVEFORMATPCMEX* format, | 777 const WAVEFORMATPCMEX* format, |
| 806 HANDLE event_handle, | 778 HANDLE event_handle, |
| 807 uint32_t* endpoint_buffer_size, | 779 uint32_t* endpoint_buffer_size, |
| 808 const GUID* session_guid) { | 780 const GUID* session_guid) { |
| 809 DCHECK(IsSupported()); | |
| 810 | |
| 811 // Use default flags (i.e, dont set AUDCLNT_STREAMFLAGS_NOPERSIST) to | 781 // Use default flags (i.e, dont set AUDCLNT_STREAMFLAGS_NOPERSIST) to |
| 812 // ensure that the volume level and muting state for a rendering session | 782 // ensure that the volume level and muting state for a rendering session |
| 813 // are persistent across system restarts. The volume level and muting | 783 // are persistent across system restarts. The volume level and muting |
| 814 // state for a capture session are never persistent. | 784 // state for a capture session are never persistent. |
| 815 DWORD stream_flags = 0; | 785 DWORD stream_flags = 0; |
| 816 | 786 |
| 817 // Enable event-driven streaming if a valid event handle is provided. | 787 // Enable event-driven streaming if a valid event handle is provided. |
| 818 // After the stream starts, the audio engine will signal the event handle | 788 // After the stream starts, the audio engine will signal the event handle |
| 819 // to notify the client each time a buffer becomes ready to process. | 789 // to notify the client each time a buffer becomes ready to process. |
| 820 // Event-driven buffering is supported for both rendering and capturing. | 790 // Event-driven buffering is supported for both rendering and capturing. |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 858 // TODO(henrika): utilize when delay measurements are added. | 828 // TODO(henrika): utilize when delay measurements are added. |
| 859 REFERENCE_TIME latency = 0; | 829 REFERENCE_TIME latency = 0; |
| 860 hr = client->GetStreamLatency(&latency); | 830 hr = client->GetStreamLatency(&latency); |
| 861 DVLOG(2) << "stream latency: " | 831 DVLOG(2) << "stream latency: " |
| 862 << RefererenceTimeToTimeDelta(latency).InMillisecondsF() << " [ms]"; | 832 << RefererenceTimeToTimeDelta(latency).InMillisecondsF() << " [ms]"; |
| 863 return hr; | 833 return hr; |
| 864 } | 834 } |
| 865 | 835 |
| 866 ScopedComPtr<IAudioRenderClient> CoreAudioUtil::CreateRenderClient( | 836 ScopedComPtr<IAudioRenderClient> CoreAudioUtil::CreateRenderClient( |
| 867 IAudioClient* client) { | 837 IAudioClient* client) { |
| 868 DCHECK(IsSupported()); | |
| 869 | |
| 870 // Get access to the IAudioRenderClient interface. This interface | 838 // Get access to the IAudioRenderClient interface. This interface |
| 871 // enables us to write output data to a rendering endpoint buffer. | 839 // enables us to write output data to a rendering endpoint buffer. |
| 872 ScopedComPtr<IAudioRenderClient> audio_render_client; | 840 ScopedComPtr<IAudioRenderClient> audio_render_client; |
| 873 HRESULT hr = client->GetService(__uuidof(IAudioRenderClient), | 841 HRESULT hr = client->GetService(__uuidof(IAudioRenderClient), |
| 874 audio_render_client.ReceiveVoid()); | 842 audio_render_client.ReceiveVoid()); |
| 875 if (FAILED(hr)) { | 843 if (FAILED(hr)) { |
| 876 DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr; | 844 DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr; |
| 877 return ScopedComPtr<IAudioRenderClient>(); | 845 return ScopedComPtr<IAudioRenderClient>(); |
| 878 } | 846 } |
| 879 return audio_render_client; | 847 return audio_render_client; |
| 880 } | 848 } |
| 881 | 849 |
| 882 ScopedComPtr<IAudioCaptureClient> CoreAudioUtil::CreateCaptureClient( | 850 ScopedComPtr<IAudioCaptureClient> CoreAudioUtil::CreateCaptureClient( |
| 883 IAudioClient* client) { | 851 IAudioClient* client) { |
| 884 DCHECK(IsSupported()); | |
| 885 | |
| 886 // Get access to the IAudioCaptureClient interface. This interface | 852 // Get access to the IAudioCaptureClient interface. This interface |
| 887 // enables us to read input data from a capturing endpoint buffer. | 853 // enables us to read input data from a capturing endpoint buffer. |
| 888 ScopedComPtr<IAudioCaptureClient> audio_capture_client; | 854 ScopedComPtr<IAudioCaptureClient> audio_capture_client; |
| 889 HRESULT hr = client->GetService(__uuidof(IAudioCaptureClient), | 855 HRESULT hr = client->GetService(__uuidof(IAudioCaptureClient), |
| 890 audio_capture_client.ReceiveVoid()); | 856 audio_capture_client.ReceiveVoid()); |
| 891 if (FAILED(hr)) { | 857 if (FAILED(hr)) { |
| 892 DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr; | 858 DVLOG(1) << "IAudioClient::GetService: " << std::hex << hr; |
| 893 return ScopedComPtr<IAudioCaptureClient>(); | 859 return ScopedComPtr<IAudioCaptureClient>(); |
| 894 } | 860 } |
| 895 return audio_capture_client; | 861 return audio_capture_client; |
| 896 } | 862 } |
| 897 | 863 |
| 898 bool CoreAudioUtil::FillRenderEndpointBufferWithSilence( | 864 bool CoreAudioUtil::FillRenderEndpointBufferWithSilence( |
| 899 IAudioClient* client, IAudioRenderClient* render_client) { | 865 IAudioClient* client, IAudioRenderClient* render_client) { |
| 900 DCHECK(IsSupported()); | |
| 901 | |
| 902 UINT32 endpoint_buffer_size = 0; | 866 UINT32 endpoint_buffer_size = 0; |
| 903 if (FAILED(client->GetBufferSize(&endpoint_buffer_size))) | 867 if (FAILED(client->GetBufferSize(&endpoint_buffer_size))) |
| 904 return false; | 868 return false; |
| 905 | 869 |
| 906 UINT32 num_queued_frames = 0; | 870 UINT32 num_queued_frames = 0; |
| 907 if (FAILED(client->GetCurrentPadding(&num_queued_frames))) | 871 if (FAILED(client->GetCurrentPadding(&num_queued_frames))) |
| 908 return false; | 872 return false; |
| 909 | 873 |
| 910 BYTE* data = NULL; | 874 BYTE* data = NULL; |
| 911 int num_frames_to_fill = endpoint_buffer_size - num_queued_frames; | 875 int num_frames_to_fill = endpoint_buffer_size - num_queued_frames; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 965 | 929 |
| 966 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { | 930 if (variant.type() == VT_BSTR && variant.ptr()->bstrVal) { |
| 967 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), | 931 base::WideToUTF8(variant.ptr()->bstrVal, wcslen(variant.ptr()->bstrVal), |
| 968 driver_version); | 932 driver_version); |
| 969 } | 933 } |
| 970 | 934 |
| 971 return true; | 935 return true; |
| 972 } | 936 } |
| 973 | 937 |
| 974 } // namespace media | 938 } // namespace media |
| OLD | NEW |