再论COM组件
重要的Activate方法
Activate方法
Activate支持的接口
源码分析
h:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\media\engine\webrtc_voice_engine.cc
WebRtcVoiceEngine::Init
void WebRtcVoiceEngine::Init() {
***
RTC_CHECK(adm());
webrtc::adm_helpers::Init(adm());
***
}
这时候进入到
H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\media\engine\adm_helpers.cc
void Init(AudioDeviceModule* adm) 方法
webrtc::adm_helpers::Init
void Init(AudioDeviceModule* adm) {
RTC_DCHECK(adm);
RTC_CHECK_EQ(0, adm->Init()) << "Failed to initialize the ADM.";
// Playout device.
{
if (adm->SetPlayoutDevice(AUDIO_DEVICE_ID) != 0) {
RTC_LOG(LS_ERROR) << "Unable to set playout device.";
return;
}
if (adm->InitSpeaker() != 0) {
RTC_LOG(LS_ERROR) << "Unable to access speaker.";
}
// Set number of channels
bool available = false;
if (adm->StereoPlayoutIsAvailable(&available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to query stereo playout.";
}
if (adm->SetStereoPlayout(available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to set stereo playout mode.";
}
}
// Recording device.
{
if (adm->SetRecordingDevice(AUDIO_DEVICE_ID) != 0) {
RTC_LOG(LS_ERROR) << "Unable to set recording device.";
return;
}
if (adm->InitMicrophone() != 0) {
RTC_LOG(LS_ERROR) << "Unable to access microphone.";
}
// Set number of channels
bool available = false;
if (adm->StereoRecordingIsAvailable(&available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to query stereo recording.";
}
if (adm->SetStereoRecording(available) != 0) {
RTC_LOG(LS_ERROR) << "Failed to set stereo recording mode.";
}
}
}
AudioDeviceModuleImpl::Init
int32_t AudioDeviceModuleImpl::Init() {
RTC_LOG(INFO) << __FUNCTION__;
if (initialized_)
return 0;
RTC_CHECK(audio_device_);
AudioDeviceGeneric::InitStatus status = audio_device_->Init();
RTC_HISTOGRAM_ENUMERATION(
"WebRTC.Audio.InitializationResult", static_cast<int>(status),
static_cast<int>(AudioDeviceGeneric::InitStatus::NUM_STATUSES));
if (status != AudioDeviceGeneric::InitStatus::OK) {
RTC_LOG(LS_ERROR) << "Audio device initialization failed.";
return -1;
}
initialized_ = true;
return 0;
}
重点是音频设备初始化 AudioDeviceGeneric::InitStatus status = audiodevice->Init();
AudioDeviceGeneric::InitStatus AudioDeviceWindowsCore::Init()
AudioDeviceGeneric::InitStatus AudioDeviceWindowsCore::Init() {
MutexLock lock(&mutex_);
if (_initialized) {
return InitStatus::OK;
}
// Enumerate all audio rendering and capturing endpoint devices.
// Note that, some of these will not be able to select by the user.
// The complete collection is for internal use only.
_EnumerateEndpointDevicesAll(eRender);
_EnumerateEndpointDevicesAll(eCapture);
_initialized = true;
return InitStatus::OK;
}
调用堆栈
列出设备_EnumerateEndpointDevicesAll
AudioDeviceWindowsCore::_EnumerateEndpointDevicesAll
列出某个种类的设备,采集还是播放的设备。
int32_t AudioDeviceWindowsCore::_EnumerateEndpointDevicesAll(
***
HRESULT hr = S_OK;
IMMDeviceCollection* pCollection = NULL;
IMMDevice* pEndpoint = NULL;
IPropertyStore* pProps = NULL;
IAudioEndpointVolume* pEndpointVolume = NULL;
LPWSTR pwszID = NULL;
// Generate a collection of audio endpoint devices in the system.
// Get states for *all* endpoint devices.
// Output: IMMDeviceCollection interface.
hr = _ptrEnumerator->EnumAudioEndpoints(
dataFlow, // data-flow direction (input parameter)
DEVICE_STATE_ACTIVE | DEVICE_STATE_DISABLED | DEVICE_STATE_UNPLUGGED,
&pCollection); // release interface when done
EXIT_ON_ERROR(hr);
***
// Retrieve a count of the devices in the device collection.
hr = pCollection->GetCount(&count);
***
// Each loop prints the name of an endpoint device.
for (ULONG i = 0; i < count; i++) {
RTC_LOG(LS_VERBOSE) << "Endpoint " << i << ":";
// Get pointer to endpoint number i.
// Output: IMMDevice interface.
// 拿到一个具体的设备
hr = pCollection->Item(i, &pEndpoint);
CONTINUE_ON_ERROR(hr);
// Get the endpoint ID string (uniquely identifies the device among all
// audio endpoint devices)
hr = pEndpoint->GetId(&pwszID);
CONTINUE_ON_ERROR(hr);
RTC_LOG(LS_VERBOSE) << "ID string : " << pwszID;
// Retrieve an interface to the device's property store.
// Output: IPropertyStore interface. 获取设备属性
hr = pEndpoint->OpenPropertyStore(STGM_READ, &pProps);
CONTINUE_ON_ERROR(hr);
// use the IPropertyStore interface...
PROPVARIANT varName;
// Initialize container for property value.
PropVariantInit(&varName);
// Get the endpoint's friendly-name property.
// Example: "Speakers (Realtek High Definition Audio)"
hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
CONTINUE_ON_ERROR(hr);
RTC_LOG(LS_VERBOSE) << "friendly name: \"" << varName.pwszVal << "\"";
// 获取设备的状态
// Get the endpoint's current device state
DWORD dwState;
hr = pEndpoint->GetState(&dwState);
CONTINUE_ON_ERROR(hr);
if (dwState & DEVICE_STATE_ACTIVE)
RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
<< ") : *ACTIVE*";
if (dwState & DEVICE_STATE_DISABLED)
RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
<< ") : DISABLED";
if (dwState & DEVICE_STATE_NOTPRESENT)
RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
<< ") : NOTPRESENT";
if (dwState & DEVICE_STATE_UNPLUGGED)
RTC_LOG(LS_VERBOSE) << "state (0x" << rtc::ToHex(dwState)
<< ") : UNPLUGGED";
// Check the hardware volume capabilities.
DWORD dwHwSupportMask = 0;
hr = pEndpoint->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,
(void**)&pEndpointVolume);
CONTINUE_ON_ERROR(hr);
// 获取掩码从而得知支持什么控制
hr = pEndpointVolume->QueryHardwareSupport(&dwHwSupportMask);
CONTINUE_ON_ERROR(hr);
if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME)
// The audio endpoint device supports a hardware volume control
RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
<< ") : HARDWARE_SUPPORT_VOLUME";
if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_MUTE)
// The audio endpoint device supports a hardware mute control
RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
<< ") : HARDWARE_SUPPORT_MUTE";
if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_METER)
// The audio endpoint device supports a hardware peak meter
RTC_LOG(LS_VERBOSE) << "hwmask (0x" << rtc::ToHex(dwHwSupportMask)
<< ") : HARDWARE_SUPPORT_METER";
// Check the channel count (#channels in the audio stream that enters or
// leaves the audio endpoint device)
UINT nChannelCount(0);
hr = pEndpointVolume->GetChannelCount(&nChannelCount);
CONTINUE_ON_ERROR(hr);
RTC_LOG(LS_VERBOSE) << "#channels : " << nChannelCount;
if (dwHwSupportMask & ENDPOINT_HARDWARE_SUPPORT_VOLUME) {
// Get the volume range.
float fLevelMinDB(0.0);
float fLevelMaxDB(0.0);
float fVolumeIncrementDB(0.0);
hr = pEndpointVolume->GetVolumeRange(&fLevelMinDB, &fLevelMaxDB,
&fVolumeIncrementDB);
***
***
// Get information about the current step in the volume range.
// This method represents the volume level of the audio stream that enters
// or leaves the audio endpoint device as an index or "step" in a range of
// discrete volume levels. Output value nStepCount is the number of steps
// in the range. Output value nStep is the step index of the current
// volume level. If the number of steps is n = nStepCount, then step index
// nStep can assume values from 0 (minimum volume) to n ?1 (maximum
// volume).
UINT nStep(0);
UINT nStepCount(0); // 获取音量步长
hr = pEndpointVolume->GetVolumeStepInfo(&nStep, &nStepCount);
CONTINUE_ON_ERROR(hr);
RTC_LOG(LS_VERBOSE) << "volume steps : " << nStep << " (nStep), "
<< nStepCount << " (nStepCount)";
}
****
}