Core Audio
MMDevice API (mmdeviceapi.h)
IMMDeviceEnumerator | 枚举音频设备集(IMMDeviceCollection),获取默认设备,通过ID获取设备(IMMDevice),注册通知,取消通知(IMMNotificationClient) |
IMMDeviceCollection | 音频设备集中数量,通过索引取出设备(IMMDevice) |
IMMNotificationClient | IUnknow接口,继承实现IUnknow和设备状态改变、设备增加、设备删除、默认设备改变和设备属性改变通知接口 |
IMMDevice | 激活设备、获取设备ID、获取设备状态和获取设备属性表 |
IMMEndpoint | 获取设备eRender和eCapture(通过IMMDevice查询获取) |
// IMMDeviceEnumerator
IMMDeviceEnumerator* pEnumerator = nullptr;
CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_ALL, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
// IMMDeviceCollection - DEVICE_STATE_ACTIVE 激活状态
IMMDeviceCollection* pCollection = nullptr;
pEnumerator->EnumAudioEndpoints(eAll, DEVICE_STATEMASK_ALL, &pCollection);
pCollection->GetCount(&uDeviceCount);
pCollection->Item(i, &pEndpoint);
// IMMNotificationClient
IMMNotificationClient *pClient;
pEnumerator->RegisterEndpointNotificationCallback(pClient);
pEnumerator->UnregisterEndpointNotificationCallback(pClient);
// IMMDevice 依据id通过IMMDeviceEnumerator接口可获取 - 连过设备会在枚举有记录状态不一样
IMMDevice* pMMDevice = nullptr;
pEnumerator->GetDevice(wszID.c_str(), &pMMDevice);
pEnumerator->GetDevice(eCapture, eConsole, &pMMDevice);
pMMDevice->GetId(&pwszID);
pMMDevice->GetState(&dwState);
pMMDevice->OpenPropertyStore(STGM_READ, &pProps);
IAudioClient* pAudioClient;
pMMDevice->Activate(__uuidof(IAudioClient), CLSCTX_ALL, NULL, (void**)&pAudioClient);
// IMMEndpoint
IMMEndpoint* pMMEndpoint = nullptr;
pMMDevice->QueryInterface(__uuidof(IMMEndpoint), (void**)&pMMEndpoint);
pMMEndpoint->GetDataFlow(&emEDataFlow);
class CAudioDeviceWinMgr : public IMMNotificationClient
{
public:
// IMMNotificationClient
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface);
HRESULT STDMETHODCALLTYPE OnDeviceStateChanged(LPCWSTR pwstrDeviceId,DWORD dwNewState);
HRESULT STDMETHODCALLTYPE OnDeviceAdded(LPCWSTR pwstrDeviceId);
HRESULT STDMETHODCALLTYPE OnDeviceRemoved(LPCWSTR pwstrDeviceId);
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow,ERole role,LPCWSTR pwstrDefaultDeviceId);
HRESULT STDMETHODCALLTYPE OnPropertyValueChanged(LPCWSTR pwstrDeviceId,const PROPERTYKEY key);
private:
LONG m_cRef = 0;
};
ULONG __stdcall CAudioDeviceWinMgr::AddRef()
{ return InterlockedIncrement(&m_cRef); }
ULONG __stdcall CAudioDeviceWinMgr::Release()
{
ULONG ulRef = InterlockedDecrement(&m_cRef);
if (0 == ulRef) { delete this; }
return ulRef;
}
HRESULT __stdcall CAudioDeviceWinMgr::QueryInterface(REFIID riid, VOID** ppvInterface)
{
if (IID_IUnknown == riid){
AddRef();
*ppvInterface = (IUnknown*)this;
} else if (__uuidof(IMMNotificationClient) == riid) {
AddRef();
*ppvInterface = (IMMNotificationClient*)this;
} else {
*ppvInterface = NULL;
return E_NOINTERFACE;
}
return S_OK;
}
WAS API
// IAudioClient
// 不设置事件通知可不加AUDCLNT_STREAMFLAGS_EVENTCALLBACK,不必调用SetEventHandle
// Initialize 第三个参数以100ns为单位,决定了GetBufferSize大小,而它以采样数为单位
HANDLE hSamplesReadyEvent = CreateEventEx(NULL, NULL, 0, EVENT_MODIFY_STATE | SYNCHRONIZE);
pAudioClient->GetMixFormat(&pWaveFormateEx);
pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 20000000, 0, pWaveFormateEx, NULL);
UINT32 bufferFrameCount;
m_pAudioClient->GetBufferSize(&bufferFrameCount);
pAudioClient->SetEventHandle(hSamplesReadyEvent );
IAudioCaptureClient* pCaptureClient;
pAudioClient->GetService(__uuidof(IAudioCaptureClient), (void**)&pCaptureClient);
pAudioClient->Start();
pAudioClient->Stop();
SetEvent(hSamplesReadyEvent);
CloseHandle(hSamplesReadyEvent);
// IAudioCaptureClient
// numFramesAvailable 是以采样数为单位,跟通道和采样位数无关
// 不用事件通知时可通过sleep一半buffersize的时间来进行
WaitForSingleObject(hSamplesReadyEvent, INFINITE);
pCaptureClient->GetNextPacketSize(&packetLength);
pCaptureClient->GetBuffer(&pData, &numFramesAvailable, &flags, &u64DevicePosition, &u64QPCPosition);
pCaptureClient->ReleaseBuffer(numFramesAvailable);
注意
windows com 从接口获取的结构体,字符串,都通过CoTaskMemFree 来释放内存
LPWSTR pwszID = nullptr;
pMMDevice->GetId(&pwszID);
if (pwszID) { CoTaskMemFree(pwszID); }
WAVEFORMATEX* pWaveFormateEx = nullptr;
pAudioClient->GetMixFormat(&pWaveFormateEx);
if (pWaveFormateEx) { CoTaskMemFree(pWaveFormateEx); }
windows 通用变量 用法(有待完善)
IPropertyStore* pProps;
PROPVARIANT varName;
::PropVariantInit(&varName);
pProps->GetValue(PKEY_Device_FriendlyName, &varName);
::PropVariantClear(&varName);