本文主要從實時音視頻場景中,簡單介紹該API的使用。算法
我對實時音視頻中音頻設備的使用簡單的分爲:windows
IMMDeviceEnumerator* ptrEnumerator;
CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), reinterpret_cast<void**>(&ptrEnumerator));
並經過IMMDeviceEnumerator能夠實現:獲取系統默認設備GetDefaultAudioEndpoint、獲取設備集合IMMDeviceCollection、獲取指定設備GetDevice、註冊設備監聽IMMNotificationClient(監聽設備插拔及狀態變動)。複製代碼
首先咱們須要一個IMMDevice對象,能夠在設備管理的相關功能中獲取。緩存
IMMDevice* pDevice;
//GetDefault
ptrEnumerator->GetDefaultAudioEndpoint((EDataFlow)dir, (ERole)role/* eCommunications */, &pDevice);
//Get by path
ptrEnumerator->GetDevice(device_path, &pDevice);
//GetIndex
pCollection->Item(index, &pDevice);複製代碼
//mic capturer
ptrClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK |
AUDCLNT_STREAMFLAGS_NOPERSIST,
0,
0,
(WAVEFORMATEX*)&Wfx,
NULL);
//playout render
ptrClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_EVENTCALLBACK,
0,
0,
(WAVEFORMATEX*)&Wfx,
NULL);
//playout capturer
ptrClient->Initialize(
AUDCLNT_SHAREMODE_SHARED,
AUDCLNT_STREAMFLAGS_LOOPBACK,
0,
0,
(WAVEFORMATEX*)&Wfx,
NULL); 複製代碼
IDeviceTopology* pTopo;
pDevice->Activate(__uuidof(IDeviceTopology), CLSCTX_INPROC_SERVER, 0,&pTopo);複製代碼
麥克風採集:安全
揚聲器播放:bash
揚聲器採集:多線程
//capturer
IAudioCaptureClient* ptrCaptureClient;//audioin or audioout
ptrClient->GetService(__uuidof(IAudioCaptureClient), (void**)&ptrCaptureClient);
{//work thread
//Wait Event
ptrCaptureClient->GetBuffer(
&pData, // packet which is ready to be read by used
&framesAvailable, // #frames in the captured packet (can be zero)
&flags, // support flags (check)
&recPos, // device position of first audio frame in data packet
&recTime); // value of performance counter at the time of recording
//pData processing
ptrCaptureClient->ReleaseBuffer(framesAvailable);
}
//render
IAudioRenderClient* ptrRenderClient;//audioout
ptrClient->GetService(__uuidof(IAudioRenderClient), (void**)&ptrRenderClient);
{//work thread
BYTE* pData;//form buffer
UINT32 bufferLength = 0;
ptrClient->GetBufferSize(&bufferLength);
UINT32 playBlockSize = nSamplesPerSec / 100;
//Wait Event
UINT32 padding = 0;
ptrClient->GetCurrentPadding(&padding);
if (bufferLength - padding > playBlockSize)
{
ptrRenderClient->GetBuffer(playBlockSize, &pData);
//request and getdata
ptrCaptureClient->ReleaseBuffer(playBlockSize, 0);
}
} 複製代碼
在整個音視頻系統中,設備數據線程還須要統計數據處理時長、採集播放緩存大小等,用戶監聽檢查設備狀態及aec延遲計算。函數
IAudioEndpointVolume* pVolume;
pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, reinterpret_cast<void**>(&pVolume));複製代碼
pVolume->GetMasterVolumeLevelScalar(&fLevel);
pVolume->SetMasterVolumeLevelScalar(fLevel, NULL);複製代碼
BOOL mute;
pVolume->GetMute(&mute);
pVolume->SetMute(mute, NULL);複製代碼
IAudioEndpointVolumeCallback* cbSessionVolume;//need to do
pVolume->RegisterControlChangeNotify(cbSessionVolume);複製代碼
IAudioSessionControl* ptrSessionControl;
ptrClient->GetService(__uuidof(IAudioSessionControl), (void**)&ptrSessionControl);
IAudioSessionEvents* notify;
ptrSessionControl->RegisterAudioSessionNotification(notify);複製代碼
avrt_module_ = LoadLibrary(TEXT("Avrt.dll"));
if (avrt_module_)
{
_PAvRevertMmThreadCharacteristics = (PAvRevertMmThreadCharacteristics)GetProcAddress(avrt_module_, "AvRevertMmThreadCharacteristics");
_PAvSetMmThreadCharacteristicsA = (PAvSetMmThreadCharacteristicsA)GetProcAddress(avrt_module_, "AvSetMmThreadCharacteristicsA");
_PAvSetMmThreadPriority = (PAvSetMmThreadPriority)GetProcAddress(avrt_module_, "AvSetMmThreadPriority");
}複製代碼
hMmTask_ = _PAvSetMmThreadCharacteristicsA("Pro Audio", &taskIndex);
if (hMmTask_)
{
_PAvSetMmThreadPriority(hMmTask_, AVRT_PRIORITY_CRITICAL);
}複製代碼