前言概念
WindowsCore的构造函数
STA与MTA
STA: Single-Thread Apartment, 中文叫单线程套间。就是在COM库初始化的时候创建一个内存结构,然后让它和调用CoInitialize的线程相关联。这个内存结构针对每个线程都会有一个。支持STA的COM对象只能在创建它的线程里被使用,其它线程如果再创建它就会失败。
MTA: Mutil-Thread Apartment,中文叫多线程套间。COM库在进程中创建一个内存结构,这个内存结构在整个进程中只能有一个,然后让它和调用CoInitializeEx的线程相关联。支持MTA的COM对象可以在任意线程里被使用。多有针对它的调用都会被封装成为消息。
其实STA和MTA是COM规定的一套线程模型,用于保障多线程情况下你的组件代码的同步。比如说有一个COM对象它内部有一个静态变量 gHello,那么这个对象无论生成多少实例对于gHello在内存中只能有一份,那么如果有两个不同的实例在两个线程里面同时去读写它,就有可能出错,所以就要就要有种机制进行同步保护,STA或者MTA就是这种机制。
AVRT库
DMO
源码分析
WebRtcVoiceEngine::Init
直接打断点
H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\media\engine\webrtc_voice_engine.cc
WebRtcVoiceEngine::Init
调用堆栈
cricket::ChannelManager::Init
->
cricket::CompositeMediaEngine::Init()
->
cricket::WebRtcVoiceEngine::Init()
AudioDeviceWindowsCore::AudioDeviceWindowsCore
打断点
H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\modules\audio_device\win\audio_device_core_win.cc 构造函数的398行
调用堆栈
AudioDeviceWindowsCore::AudioDeviceWindowsCore()
: _avrtLibrary(NULL),
_winSupportAvrt(false),
_comInit(ScopedCOMInitializer::kMTA),
_ptrAudioBuffer(NULL),
_ptrEnumerator(NULL),
_ptrRenderCollection(NULL),
_ptrCaptureCollection(NULL),
_ptrDeviceOut(NULL),
_ptrDeviceIn(NULL),
_ptrClientOut(NULL),
_ptrClientIn(NULL),
_ptrRenderClient(NULL),
_ptrCaptureClient(NULL),
_ptrCaptureVolume(NULL),
_ptrRenderSimpleVolume(NULL),
_dmo(NULL),
_mediaBuffer(NULL),
_builtInAecEnabled(false),
_hRenderSamplesReadyEvent(NULL),
_hPlayThread(NULL),
_hRenderStartedEvent(NULL),
_hShutdownRenderEvent(NULL),
_hCaptureSamplesReadyEvent(NULL),
_hRecThread(NULL),
_hCaptureStartedEvent(NULL),
_hShutdownCaptureEvent(NULL),
_hMmTask(NULL),
_playAudioFrameSize(0),
_playSampleRate(0),
_playBlockSize(0),
_playChannels(2),
_sndCardPlayDelay(0),
_writtenSamples(0),
_readSamples(0),
_recAudioFrameSize(0),
_recSampleRate(0),
_recBlockSize(0),
_recChannels(2),
_initialized(false),
_recording(false),
_playing(false),
_recIsInitialized(false),
_playIsInitialized(false),
_speakerIsInitialized(false),
_microphoneIsInitialized(false),
_usingInputDeviceIndex(false),
_usingOutputDeviceIndex(false),
_inputDevice(AudioDeviceModule::kDefaultCommunicationDevice),
_outputDevice(AudioDeviceModule::kDefaultCommunicationDevice),
_inputDeviceIndex(0),
_outputDeviceIndex(0) {
RTC_DLOG(LS_INFO) << __FUNCTION__ << " created";
RTC_DCHECK(_comInit.Succeeded());
// Try to load the Avrt DLL
if (!_avrtLibrary) {
// Get handle to the Avrt DLL module.
_avrtLibrary = LoadLibrary(TEXT("Avrt.dll"));
if (_avrtLibrary) {
// Handle is valid (should only happen if OS larger than vista & win7).
// Try to get the function addresses.
RTC_LOG(LS_VERBOSE) << "AudioDeviceWindowsCore::AudioDeviceWindowsCore()"
" The Avrt DLL module is now loaded";
// 获取三个方法
_PAvRevertMmThreadCharacteristics =
(PAvRevertMmThreadCharacteristics)GetProcAddress(
_avrtLibrary, "AvRevertMmThreadCharacteristics");
_PAvSetMmThreadCharacteristicsA =
(PAvSetMmThreadCharacteristicsA)GetProcAddress(
_avrtLibrary, "AvSetMmThreadCharacteristicsA");
_PAvSetMmThreadPriority = (PAvSetMmThreadPriority)GetProcAddress(
_avrtLibrary, "AvSetMmThreadPriority");
if (_PAvRevertMmThreadCharacteristics &&
_PAvSetMmThreadCharacteristicsA && _PAvSetMmThreadPriority) {
RTC_LOG(LS_VERBOSE)
<< "AudioDeviceWindowsCore::AudioDeviceWindowsCore()"
" AvRevertMmThreadCharacteristics() is OK";
RTC_LOG(LS_VERBOSE)
<< "AudioDeviceWindowsCore::AudioDeviceWindowsCore()"
" AvSetMmThreadCharacteristicsA() is OK";
RTC_LOG(LS_VERBOSE)
<< "AudioDeviceWindowsCore::AudioDeviceWindowsCore()"
" AvSetMmThreadPriority() is OK";
// 设置标志
_winSupportAvrt = true;
}
}
}
// Create our samples ready events - we want auto reset events that start in
// the not-signaled state. The state of an auto-reset event object remains
// signaled until a single waiting thread is released, at which time the
// system automatically sets the state to nonsignaled. If no threads are
// waiting, the event object's state remains signaled. (Except for
// _hShutdownCaptureEvent, which is used to shutdown multiple threads).
_hRenderSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
_hCaptureSamplesReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
_hShutdownRenderEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
_hShutdownCaptureEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
_hRenderStartedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
_hCaptureStartedEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
_perfCounterFreq.QuadPart = 1;
_perfCounterFactor = 0.0;
// list of number of channels to use on recording side
_recChannelsPrioList[0] = 2; // stereo is prio 1
_recChannelsPrioList[1] = 1; // mono is prio 2
_recChannelsPrioList[2] = 4; // quad is prio 3
// list of number of channels to use on playout side
_playChannelsPrioList[0] = 2; // stereo is prio 1
_playChannelsPrioList[1] = 1; // mono is prio 2
HRESULT hr;
// We know that this API will work since it has already been verified in
// CoreAudioIsSupported, hence no need to check for errors here as well.
// Retrive the IMMDeviceEnumerator API (should load the MMDevAPI.dll)
// TODO(henrika): we should probably move this allocation to Init() instead
// and deallocate in Terminate() to make the implementation more symmetric.
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL,
__uuidof(IMMDeviceEnumerator),
reinterpret_cast<void**>(&_ptrEnumerator));
assert(NULL != _ptrEnumerator);
// DMO初始化,主要用于回音消除,硬件层次。如果是软件层次,就是WebRTC的算法了。
// 苹果手机,硬件。。Windows一般使用软件。
// DMO initialization for built-in WASAPI AEC.
{
IMediaObject* ptrDMO = NULL;
hr = CoCreateInstance(CLSID_CWMAudioAEC, NULL, CLSCTX_INPROC_SERVER,
IID_IMediaObject, reinterpret_cast<void**>(&ptrDMO));
if (FAILED(hr) || ptrDMO == NULL) {
// Since we check that _dmo is non-NULL in EnableBuiltInAEC(), the
// feature is prevented from being enabled.
_builtInAecEnabled = false;
_TraceCOMError(hr);
}
_dmo = ptrDMO;
SAFE_RELEASE(ptrDMO);
}
}
其中ScopedCOMInitializer _comInit;
去到该类的定义去,可以发现,选择的是MTA 多线程套间。
class ScopedCOMInitializer {
public:
enum SelectMTA { kMTA };
explicit ScopedCOMInitializer(SelectMTA mta);
}