最近在做winsows上音頻方面的程序,用到Core Audio APIs系列API來設置相關音頻設備參數(shù),所以對用到這方面的知識做一個總結。Core Audio APIs是Windows Vista家族后提供一套新的底層API,主要有以下幾個內(nèi)容
Multimedia Device (MMDevice) API:用來枚舉操作系統(tǒng)自帶的音頻終端設備對象。
Windows Audio Session API (WASAPI):根據(jù)第一步枚舉處理終端設備對象創(chuàng)建和管理音頻流。
DeviceTopology API:使用此類API可以直接訪問音頻適配器中的硬件數(shù)據(jù)通路的拓撲特性(如音量控制,多路復用器等)。
EndpointVolume API:使用此類API可以直接訪問音頻設備的聲音控制,這類API主要是給那些毒戰(zhàn)模式管理音頻流的應用程序。
下面讓我們用代碼事例設置麥克風和揚聲器音量大小,以及設置麥克風加強來說明相關用法:
1. 首先我們定義相關COM接口如下,后面要用到:
CComPtr<IMMDeviceEnumerator > m_pIMMEnumerator; //主要用于枚舉設備接口 CComPtr<IAudioEndpointVolume> m_pRenderEndptVol; //揚聲器音量控制接口 CComPtr<ISimpleAudioVolume> m_pRenderSimpleVol; //揚聲器的會話音量控制接口
2.創(chuàng)建IMMDeviceEnumerator接口,IMMDeviceEnumerator接口是獲取后面設備對象的根本,所以先要創(chuàng)建這個接口,用常用創(chuàng)建COM接口的CoCreateInstance()來創(chuàng)建,指定相應的參數(shù),很基本用法,不做過多說明。
hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, (void**)&m_pIMMEnumerator);
pIMMEnumerator對象創(chuàng)建好,我們可以看看這個接口可以用的方法:
class IMMDeviceEnumerator : public IUnknown virtual HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices) = 0; virtual HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint) = 0; virtual HRESULT STDMETHODCALLTYPE GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice) = 0; virtual HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(IMMNotificationClient *pClient) = 0; virtual HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(IMMNotificationClient *pClient) = 0;
可以看到除過IUnKonwn接口方法外有屬于自己的五個方法,分別如下:
EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices); //獲取系統(tǒng)默認音頻設備,類似主音頻設備 GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint); //根據(jù)設備ID獲取指定的設備,設備ID可以通過EnumAudioEndpoints()獲取,也可以通過DSound函數(shù)DirectSoundEnumerate()等獲取。 GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice); //注冊給終端設備一些通知事件,注冊后比如當設備撥出、插入、有變化時會收到相應的通知事件。 RegisterEndpointNotificationCallback(IMMNotificationClient *pClient); UnregisterEndpointNotificationCallback();
本次我們主要是用GetDefaultAudioEndpoint()和GetDevice()這兩個接口方法。
4.獲取IAudioEndpointVolume揚聲器m_pRenderEndptVol接口,首先我們要定義一個IMMDevice對象,根據(jù)剛剛創(chuàng)建的m_pIMMEnumerator對象獲取相應的IMMDevice對象,然后用獲取的IMMDevice對象激活m_pRenderEndptVol接口。
如果之前沒有獲取終端ID則可以使用
//eAll : 會列舉出系統(tǒng)中所有的音頻設備包括Render --- 揚聲器, Capture --- Microphone, Stereo Mixer; //eRender: 會列舉出系統(tǒng)中所有的音頻播放設備; //eCapture: 會列舉出系統(tǒng)中所有音頻采集設備; //ERole 設備角色,假如系統(tǒng)中有多個音頻設備,那么一個設備可能用戶是用來播放電影的,另一個可能是用來玩游戲的,因此就引入了角色的概念。 //eConsole : 與計算機交互; eCommunications : 與他人的聲音交流; eMultimedia : 播放或者錄制電影和音樂,一般默認使用eConsole。 //ppEndpoint:需要接收獲取設備對象指針。 HRESULT GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint);
如果之前已經(jīng)枚舉出設備ID,想要根據(jù)設備ID過去指定的設備對象,可以使用
//pwstrId: 已經(jīng)獲取的設備ID; //ppDevice:需要接收獲取設備對象二重指針; HRESULT GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice)
示例代碼如下:
CComPtr<IMMDevice> pIMMDeivce = NULL; if(strEndPointID.empty()) hr = m_pIMMEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&pIMMDeivce); hr = m_pIMMEnumerator->GetDevice(strEndPointID.c_s(),&pIMMDeivce);
獲取pIMMDeivce對象后,就可以用這個對象接口激活自己想要控制的相應音量設備的接口了,先看下IMMDevice接口擁有屬于自己的方法:class IMMDevice : public IUnknown virtual HRESULT STDMETHODCALLTYPE Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) = 0; virtual HRESULT STDMETHODCALLTYPE OpenPropertyStore(DWORD stgmAccess,IPropertyStore **ppProperties) = 0; virtual HRESULT STDMETHODCALLTYPE GetId(LPWSTR *ppstrId) = 0; virtual HRESULT STDMETHODCALLTYPE GetState(DWORD *pdwState) = 0;
簡單注釋下這個幾個函數(shù)意義://dwClsCtx:執(zhí)行上下文,一般指定CLSCTX_ALL獲取所有信息; //pActivationParams:對于IID_IAudioEndpointVolume接口設置為NULL。 //ppInterface:需要接收獲取設備對象二重指針; HRESULT Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) HRESULT OpenPropertyStore(DWORD stgmAccess,IPropertyStore **ppProperties) HRESULT GetId(LPWSTR *ppstrId) HRESULT GetState(DWORD *pdwState)
我們主要用的是Activate()方法,首先我們獲取揚聲器音量控制接口m_pRenderEndptVol,如下hr = pIMMDeivce->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&m_pRenderEndptVol);
獲取到m_pRenderEndptVol接口后我們就可以用這個接口設置系統(tǒng)揚聲器音量了。
5.設置系統(tǒng)揚聲器音量,也就是主音量,先看看剛剛我們獲取m_pRenderEndptVol接口擁有屬于自己的方法:class IAudioEndpointVolume : public IUnknown virtual HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) = 0; virtual HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) = 0; virtual HRESULT STDMETHODCALLTYPE GetChannelCount(UINT *pnChannelCount) = 0; virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel(float fLevelDB,LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar(float fLevel,LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel(float *pfLevelDB) = 0; virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar(float *pfLevel) = 0; virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel(UINT nChannel,float fLevelDB,LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar(UINT nChannel,float fLevel,LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel(UINT nChannel,float *pfLevelDB) = 0; virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar(UINT nChannel,float *pfLevel) = 0; virtual HRESULT STDMETHODCALLTYPE SetMute(BOOL bMute,LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE GetMute(BOOL *pbMute) = 0; virtual HRESULT STDMETHODCALLTYPE GetVolumeStepInfo(UINT *pnStep,UINT *pnStepCount) = 0; virtual HRESULT STDMETHODCALLTYPE VolumeStepUp(LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE VolumeStepDown(LPCGUID pguidEventContext) = 0; virtual HRESULT STDMETHODCALLTYPE QueryHardwareSupport(DWORD *pdwHardwareSupportMask) = 0; virtual HRESULT STDMETHODCALLTYPE GetVolumeRange(float *pflVolumeMindB,float *pflVolumeMaxdB,float *pflVolumeIncrementdB) = 0;
這個IAudioEndpointVolume接口方法很多,不仔細介紹每一個了,只介紹我們需要用到的幾個方法,大家可以根據(jù)自己的需要,顧名思義找到自己需要用的方法。fLevel:主音量數(shù)值級別,這個值范圍在0到1之間; pguidEventContext):此參數(shù)指向一個事件上下文的GUID,如果SetMasterVolumeLevelScalar調(diào)用更改端點的音量,所有已注冊客戶IAudioEndpointVolumeCallback接口與端點將接收通知。 HRESULT SetMasterVolumeLevelScalar(float fLevel,LPCGUID pguidEventContext); HRESULT GetMasterVolumeLevelScalar(float *pfLevel); HRESULT SetMute(BOOL bMute,LPCGUID pguidEventContext); HRESULT GetMute(BOOL *pbMute);
其余幾個參數(shù)很簡單,看名字就知道什么意思,不作過多介紹。
設置系統(tǒng)揚聲器音量代碼示例:
float level = 0.5f;//這個值可以跟進相應比例換算所得 hr = m_pRenderEndptVol->SetMasterVolumeLevelScalar(level, NULL);
獲取系統(tǒng)揚聲器音量代碼示例:hr = m_pRenderEndptVol->GetMasterVolumeLevelScalar(&level);
注意level這個值一般根據(jù)界面滑動條最大值按比例換算所得。
設置系統(tǒng)揚聲器靜音示例:hr = m_pRenderSimpleVol->SetMute(TRUE, NULL);
獲取系統(tǒng)揚聲器靜音狀態(tài)示例:
hr = m_pRenderSimpleVol->GetMute(&bMute);
這只是簡單的幾種參數(shù)設置,大家可以根據(jù)自己的需要來選擇不同方法達到自己目的。
6.設置應用程序會話音量
上面設置的都是系統(tǒng)揚聲器的音量,即相應的設置會影響系統(tǒng)上所有軟件的音量,下面我們來設置屬于應用程序本身的會話音量,所謂會話音量即時這個應用程序本身的音量,設置會話音量的大小只會影響應用程序本身的音量大小,不會影響系統(tǒng)其它程序音量的大小。首先我們要獲取IAudioSessionManager接口對象,方法是通過已經(jīng)獲取IMMDevice接口對象來激活IAudioSessionManager接口對象,然后就可以通過IAudioSessionManager接口來獲取ISimpleAudioVolume接口對象了,最后通過ISimpleAudioVolume接口對象就可以操作會話音量的大小了。示例代碼如下:
CComPtr<IAudioSessionManager> pSessionManager = NULL; hr = pIMMDeivce->Activate(IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, (void **)(&pSessionManager)); hr = pSessionManager->GetSimpleAudioVolume(NULL, FALSE, &m_pRenderSimpleVol);
獲取到ISimpleAudioVolume接口對象后就可以使用其具有的方法操作具體的功能了,看下這個接口有的方法:
class ISimpleAudioVolume : public IUnknown virtual HRESULT STDMETHODCALLTYPE SetMasterVolume(float fLevel, LPCGUID EventContext) = 0; virtual HRESULT STDMETHODCALLTYPE GetMasterVolume(float *pfLevel) = 0; virtual HRESULT STDMETHODCALLTYPE SetMute(const BOOL bMute, LPCGUID EventContext) = 0; virtual HRESULT STDMETHODCALLTYPE GetMute(BOOL *pbMute) = 0;
所有方法和上面IAudioEndpointVolume接口方法基本一樣,直接貼代碼說明
設置和獲取會話音量的大?。?pre>hr = m_pRenderSimpleVol->SetMasterVolume(fVol, NULL); hr = m_pRenderSimpleVol->GetMasterVolume(&fVol);
設置和獲取會話音量的靜音狀態(tài):hr = m_pRenderSimpleVol->SetMute(bMute , NULL); hr = m_pRenderSimpleVol->GetMute(&bMute);
揚聲器里面的功能設置還有很多方法,介紹只是最基本的方法,大家可以根據(jù)自己需要挖掘更深層的設置方法,這一節(jié)就先介紹到這里吧,下一節(jié)介紹系統(tǒng)麥克風方面一些簡單的設置。
|