7-7 源码分析-ADM初始化之枚举音频设备 - 图1

再论COM组件

image.png

重要的Activate方法

image.png

Activate方法

image.png

Activate支持的接口

image.png

源码分析

h:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\media\engine\webrtc_voice_engine.cc

WebRtcVoiceEngine::Init

  1. void WebRtcVoiceEngine::Init() {
  2. ***
  3. RTC_CHECK(adm());
  4. webrtc::adm_helpers::Init(adm());
  5. ***
  6. }

这时候进入到
H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\media\engine\adm_helpers.cc
void Init(AudioDeviceModule* adm) 方法

webrtc::adm_helpers::Init

  1. void Init(AudioDeviceModule* adm) {
  2. RTC_DCHECK(adm);
  3. RTC_CHECK_EQ(0, adm->Init()) << "Failed to initialize the ADM.";
  4. // Playout device.
  5. {
  6. if (adm->SetPlayoutDevice(AUDIO_DEVICE_ID) != 0) {
  7. RTC_LOG(LS_ERROR) << "Unable to set playout device.";
  8. return;
  9. }
  10. if (adm->InitSpeaker() != 0) {
  11. RTC_LOG(LS_ERROR) << "Unable to access speaker.";
  12. }
  13. // Set number of channels
  14. bool available = false;
  15. if (adm->StereoPlayoutIsAvailable(&available) != 0) {
  16. RTC_LOG(LS_ERROR) << "Failed to query stereo playout.";
  17. }
  18. if (adm->SetStereoPlayout(available) != 0) {
  19. RTC_LOG(LS_ERROR) << "Failed to set stereo playout mode.";
  20. }
  21. }
  22. // Recording device.
  23. {
  24. if (adm->SetRecordingDevice(AUDIO_DEVICE_ID) != 0) {
  25. RTC_LOG(LS_ERROR) << "Unable to set recording device.";
  26. return;
  27. }
  28. if (adm->InitMicrophone() != 0) {
  29. RTC_LOG(LS_ERROR) << "Unable to access microphone.";
  30. }
  31. // Set number of channels
  32. bool available = false;
  33. if (adm->StereoRecordingIsAvailable(&available) != 0) {
  34. RTC_LOG(LS_ERROR) << "Failed to query stereo recording.";
  35. }
  36. if (adm->SetStereoRecording(available) != 0) {
  37. RTC_LOG(LS_ERROR) << "Failed to set stereo recording mode.";
  38. }
  39. }
  40. }

重点是adm->Init()

AudioDeviceModuleImpl::Init

  1. int32_t AudioDeviceModuleImpl::Init() {
  2. RTC_LOG(INFO) << __FUNCTION__;
  3. if (initialized_)
  4. return 0;
  5. RTC_CHECK(audio_device_);
  6. AudioDeviceGeneric::InitStatus status = audio_device_->Init();
  7. RTC_HISTOGRAM_ENUMERATION(
  8. "WebRTC.Audio.InitializationResult", static_cast<int>(status),
  9. static_cast<int>(AudioDeviceGeneric::InitStatus::NUM_STATUSES));
  10. if (status != AudioDeviceGeneric::InitStatus::OK) {
  11. RTC_LOG(LS_ERROR) << "Audio device initialization failed.";
  12. return -1;
  13. }
  14. initialized_ = true;
  15. return 0;
  16. }

重点是音频设备初始化 AudioDeviceGeneric::InitStatus status = audiodevice->Init();

AudioDeviceGeneric::InitStatus AudioDeviceWindowsCore::Init()

  1. AudioDeviceGeneric::InitStatus AudioDeviceWindowsCore::Init() {
  2. MutexLock lock(&mutex_);
  3. if (_initialized) {
  4. return InitStatus::OK;
  5. }
  6. // Enumerate all audio rendering and capturing endpoint devices.
  7. // Note that, some of these will not be able to select by the user.
  8. // The complete collection is for internal use only.
  9. _EnumerateEndpointDevicesAll(eRender);
  10. _EnumerateEndpointDevicesAll(eCapture);
  11. _initialized = true;
  12. return InitStatus::OK;
  13. }

调用堆栈

image.png
列出设备_EnumerateEndpointDevicesAll

AudioDeviceWindowsCore::_EnumerateEndpointDevicesAll

列出某个种类的设备,采集还是播放的设备。

  1. int32_t AudioDeviceWindowsCore::_EnumerateEndpointDevicesAll(
  2. ***
  3. HRESULT hr = S_OK;
  4. IMMDeviceCollection* pCollection = NULL;
  5. IMMDevice* pEndpoint = NULL;
  6. IPropertyStore* pProps = NULL;
  7. IAudioEndpointVolume* pEndpointVolume = NULL;
  8. LPWSTR pwszID = NULL;
  9. // Generate a collection of audio endpoint devices in the system.
  10. // Get states for *all* endpoint devices.
  11. // Output: IMMDeviceCollection interface.
  12. hr = _ptrEnumerator->EnumAudioEndpoints(
  13. dataFlow, // data-flow direction (input parameter)
  14. DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED,
  15. &pCollection); // release interface when done
  16. EXIT_ON_ERROR(hr);
  17. ***
  18. // Retrieve a count of the devices in the device collection.
  19. hr = pCollection->GetCount(&count);
  20. ***
  21. // Each loop prints the name of an endpoint device.
  22. for (ULONG i = 0; i < count; i++) {
  23. RTC_LOG(LS_VERBOSE) << "Endpoint " << i << ":";
  24. // Get pointer to endpoint number i.
  25. // Output: IMMDevice interface.
  26. // 拿到一个具体的设备
  27. hr = pCollection->Item(i, &pEndpoint);
  28. CONTINUE_ON_ERROR(hr);
  29. // Get the endpoint ID string (uniquely identifies the device among all
  30. // audio endpoint devices)
  31. hr = pEndpoint->GetId(&pwszID);
  32. CONTINUE_ON_ERROR(hr);
  33. RTC_LOG(LS_VERBOSE) << "ID string : " << pwszID;
  34. // Retrieve an interface to the device's property store.
  35. // Output: IPropertyStore interface. 获取设备属性
  36. hr = pEndpoint->OpenPropertyStore(STGM_READ, &pProps);
  37. CONTINUE_ON_ERROR(hr);
  38. // use the IPropertyStore interface...
  39. PROPVARIANT varName;
  40. // Initialize container for property value.
  41. PropVariantInit(&varName);
  42. // Get the endpoint's friendly-name property.
  43. // Example: "Speakers (Realtek High Definition Audio)"
  44. hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
  45. CONTINUE_ON_ERROR(hr);
  46. RTC_LOG(LS_VERBOSE) << "friendly name: \"" << varName.pwszVal << "\"";
  47. // 获取设备的状态
  48. // Get the endpoint's current device state
  49. DWORD dwState;
  50. hr = pEndpoint->GetState(&dwState);
  51. CONTINUE_ON_ERROR(hr);
  52. if (dwState & DEVICE_STATE_ACTIVE)
  53. RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
  54. << ") : *ACTIVE*";
  55. if (dwState & DEVICE_STATE_DISABLED)
  56. RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
  57. << ") : DISABLED";
  58. if (dwState & DEVICE_STATE_NOTPRESENT)
  59. RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
  60. << ") : NOTPRESENT";
  61. if (dwState & DEVICE_STATE_UNPLUGGED)
  62. RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
  63. << ") : UNPLUGGED";
  64. // Check the hardware volume capabilities.
  65. DWORD dwHwSupportMask = 0;
  66. hr = pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,
  67. (void**)&pEndpointVolume);
  68. CONTINUE_ON_ERROR(hr);
  69. // 获取掩码从而得知支持什么控制
  70. hr = pEndpointVolume->QueryHardwareSupport(&dwHwSupportMask);
  71. CONTINUE_ON_ERROR(hr);
  72. if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME)
  73. // The audio endpoint device supports a hardware volume control
  74. RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
  75. << ") : HARDWARE_SUPPORT_VOLUME";
  76. if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_MUTE)
  77. // The audio endpoint device supports a hardware mute control
  78. RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
  79. << ") : HARDWARE_SUPPORT_MUTE";
  80. if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_METER)
  81. // The audio endpoint device supports a hardware peak meter
  82. RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
  83. << ") : HARDWARE_SUPPORT_METER";
  84. // Check the channel count (#channels in the audio stream that enters or
  85. // leaves the audio endpoint device)
  86. UINT nChannelCount(0);
  87. hr = pEndpointVolume->GetChannelCount(&nChannelCount);
  88. CONTINUE_ON_ERROR(hr);
  89. RTC_LOG(LS_VERBOSE) << "#channels : " << nChannelCount;
  90. if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME) {
  91. // Get the volume range.
  92. float fLevelMinDB(0.0);
  93. float fLevelMaxDB(0.0);
  94. float fVolumeIncrementDB(0.0);
  95. hr = pEndpointVolume->GetVolumeRange(&fLevelMinDB, &fLevelMaxDB,
  96. &fVolumeIncrementDB);
  97. ***
  98. ***
  99. // Get information about the current step in the volume range.
  100. // This method represents the volume level of the audio stream that enters
  101. // or leaves the audio endpoint device as an index or "step" in a range of
  102. // discrete volume levels. Output value nStepCount is the number of steps
  103. // in the range. Output value nStep is the step index of the current
  104. // volume level. If the number of steps is n = nStepCount, then step index
  105. // nStep can assume values from 0 (minimum volume) to n ?1 (maximum
  106. // volume).
  107. UINT nStep(0);
  108. UINT nStepCount(0); // 获取音量步长
  109. hr = pEndpointVolume->GetVolumeStepInfo(&nStep, &nStepCount);
  110. CONTINUE_ON_ERROR(hr);
  111. RTC_LOG(LS_VERBOSE) << "volume steps : " << nStep << " (nStep), "
  112. << nStepCount << " (nStepCount)";
  113. }
  114. ****
  115. }