分享

Core Audio APIs 技术笔记一(扬声器音量设置)

 mediatv 2019-10-29

        最近在做winsows上音频方面的程序,用到Core Audio APIs系列API来设置相关音频设备参数,所以对用到这方面的知识做一个总结。Core Audio APIs是Windows Vista家族后提供一套新的底层API,主要有以下几个内容

 Multimedia Device (MMDevice) API:用来枚举操作系统自带的音频终端设备对象。
 Windows Audio Session API (WASAPI):根据第一步枚举处理终端设备对象创建和管理音频流。
 DeviceTopology API:使用此类API可以直接访问音频适配器中的硬件数据通路的拓扑特性(如音量控制,多路复用器等)。
 EndpointVolume API:使用此类API可以直接访问音频设备的声音控制,这类API主要是给那些毒战模式管理音频流的应用程序。

下面让我们用代码事例设置麦克风和扬声器音量大小,以及设置麦克风加强来说明相关用法:

  1. 首先我们定义相关COM接口如下,后面要用到:

  1. CComPtr<IMMDeviceEnumerator > m_pIMMEnumerator; //主要用于枚举设备接口
  2. CComPtr<IAudioEndpointVolume> m_pRenderEndptVol; //扬声器音量控制接口
  3. CComPtr<ISimpleAudioVolume> m_pRenderSimpleVol; //扬声器的会话音量控制接口

 2.创建IMMDeviceEnumerator接口,IMMDeviceEnumerator接口是获取后面设备对象的根本,所以先要创建这个接口,用常用创建COM接口的CoCreateInstance()来创建,指定相应的参数,很基本用法,不做过多说明。

  1. HRESULT hr = S_OK;
  2. hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_INPROC_SERVER, IID_IMMDeviceEnumerator, (void**)&m_pIMMEnumerator);

pIMMEnumerator对象创建好,我们可以看看这个接口可以用的方法:

  1. class IMMDeviceEnumerator : public IUnknown
  2. {
  3. public:
  4. virtual HRESULT STDMETHODCALLTYPE EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices) = 0;
  5. virtual HRESULT STDMETHODCALLTYPE GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint) = 0;
  6. virtual HRESULT STDMETHODCALLTYPE GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice) = 0;
  7. virtual HRESULT STDMETHODCALLTYPE RegisterEndpointNotificationCallback(IMMNotificationClient *pClient) = 0;
  8. virtual HRESULT STDMETHODCALLTYPE UnregisterEndpointNotificationCallback(IMMNotificationClient *pClient) = 0;
  9. };

可以看到除过IUnKonwn接口方法外有属于自己的五个方法,分别如下:

  1. //枚举系统所有设备
  2. EnumAudioEndpoints(EDataFlow dataFlow, DWORD dwStateMask, IMMDeviceCollection **ppDevices);
  3. //获取系统默认音频设备,类似主音频设备
  4. GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint);
  5. //根据设备ID获取指定的设备,设备ID可以通过EnumAudioEndpoints()获取,也可以通过DSound函数DirectSoundEnumerate()等获取。
  6. GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice);
  7. //注册给终端设备一些通知事件,注册后比如当设备拨出、插入、有变化时会收到相应的通知事件。
  8. RegisterEndpointNotificationCallback(IMMNotificationClient *pClient);
  9. //注销掉之前注册的通知回调。
  10. UnregisterEndpointNotificationCallback();

本次我们主要是用GetDefaultAudioEndpoint()和GetDevice()这两个接口方法。

4.获取IAudioEndpointVolume扬声器m_pRenderEndptVol接口,首先我们要定义一个IMMDevice对象,根据刚刚创建的m_pIMMEnumerator对象获取相应的IMMDevice对象,然后用获取的IMMDevice对象激活m_pRenderEndptVol接口。

如果之前没有获取终端ID则可以使用

  1. //EDataFlow/有三个常用的变量:
  2. //eAll : 会列举出系统中所有的音频设备包括Render --- 扬声器, Capture --- Microphone, Stereo Mixer;
  3. //eRender: 会列举出系统中所有的音频播放设备;
  4. //eCapture: 会列举出系统中所有音频采集设备;
  5. //ERole 设备角色,假如系统中有多个音频设备,那么一个设备可能用户是用来播放电影的,另一个可能是用来玩游戏的,因此就引入了角色的概念。
  6. //eConsole : 与计算机交互; eCommunications : 与他人的声音交流; eMultimedia : 播放或者录制电影和音乐,一般默认使用eConsole。
  7. //ppEndpoint:需要接收获取设备对象指针。
  8. HRESULT GetDefaultAudioEndpoint(EDataFlow dataFlow, ERole role, IMMDevice **ppEndpoint);

如果之前已经枚举出设备ID,想要根据设备ID过去指定的设备对象,可以使用

  1. //pwstrId: 已经获取的设备ID;
  2. //ppDevice:需要接收获取设备对象二重指针;
  3. HRESULT GetDevice(LPCWSTR pwstrId, IMMDevice **ppDevice)

示例代码如下:

  1. HRESULT hr = S_OK;
  2. CComPtr<IMMDevice> pIMMDeivce = NULL;
  3. if(strEndPointID.empty())
  4. {
  5. hr = m_pIMMEnumerator->GetDefaultAudioEndpoint(eRender,eConsole,&pIMMDeivce);
  6. }
  7. else
  8. {
  9. hr = m_pIMMEnumerator->GetDevice(strEndPointID.c_s(),&pIMMDeivce);
  10. }
获取pIMMDeivce对象后,就可以用这个对象接口激活自己想要控制的相应音量设备的接口了,先看下IMMDevice接口拥有属于自己的方法:
  1. class IMMDevice : public IUnknown
  2. {
  3. public:
  4. virtual HRESULT STDMETHODCALLTYPE Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface) = 0;
  5. virtual HRESULT STDMETHODCALLTYPE OpenPropertyStore(DWORD stgmAccess,IPropertyStore **ppProperties) = 0;
  6. virtual HRESULT STDMETHODCALLTYPE GetId(LPWSTR *ppstrId) = 0;
  7. virtual HRESULT STDMETHODCALLTYPE GetState(DWORD *pdwState) = 0;
  8. };
简单注释下这个几个函数意义:
  1. //激活这个设备下指定接口的COM对象;
  2. //iid:指定获取接口的GUID;
  3. //dwClsCtx:执行上下文,一般指定CLSCTX_ALL获取所有信息;
  4. //pActivationParams:对于IID_IAudioEndpointVolume接口设置为NULL。
  5. //ppInterface:需要接收获取设备对象二重指针;
  6. HRESULT Activate(REFIID iid, DWORD dwClsCtx, PROPVARIANT *pActivationParams, void **ppInterface)
  7. //打开一个设备的属性存储接口;
  8. HRESULT OpenPropertyStore(DWORD stgmAccess,IPropertyStore **ppProperties)
  9. //获取设备ID;
  10. HRESULT GetId(LPWSTR *ppstrId)
  11. //获取设备状态信息; 
  12. HRESULT GetState(DWORD *pdwState)  
我们主要用的是Activate()方法,首先我们获取扬声器音量控制接口m_pRenderEndptVol,如下
  1. //主声音设备
  2. hr = pIMMDeivce->Activate(IID_IAudioEndpointVolume, CLSCTX_ALL, NULL, (void**)&m_pRenderEndptVol);
获取到m_pRenderEndptVol接口后我们就可以用这个接口设置系统扬声器音量了。
5.设置系统扬声器音量,也就是主音量,先看看刚刚我们获取m_pRenderEndptVol接口拥有属于自己的方法:
  1. class IAudioEndpointVolume : public IUnknown
  2. {
  3. public:
  4. virtual HRESULT STDMETHODCALLTYPE RegisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) = 0;
  5. virtual HRESULT STDMETHODCALLTYPE UnregisterControlChangeNotify(IAudioEndpointVolumeCallback *pNotify) = 0;
  6. virtual HRESULT STDMETHODCALLTYPE GetChannelCount(UINT *pnChannelCount) = 0;
  7. virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevel(float fLevelDB,LPCGUID pguidEventContext) = 0;
  8. virtual HRESULT STDMETHODCALLTYPE SetMasterVolumeLevelScalar(float fLevel,LPCGUID pguidEventContext) = 0;
  9. virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevel(float *pfLevelDB) = 0;
  10. virtual HRESULT STDMETHODCALLTYPE GetMasterVolumeLevelScalar(float *pfLevel) = 0;
  11. virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevel(UINT nChannel,float fLevelDB,LPCGUID pguidEventContext) = 0;
  12. virtual HRESULT STDMETHODCALLTYPE SetChannelVolumeLevelScalar(UINT nChannel,float fLevel,LPCGUID pguidEventContext) = 0;
  13. virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevel(UINT nChannel,float *pfLevelDB) = 0;
  14. virtual HRESULT STDMETHODCALLTYPE GetChannelVolumeLevelScalar(UINT nChannel,float *pfLevel) = 0;
  15. virtual HRESULT STDMETHODCALLTYPE SetMute(BOOL bMute,LPCGUID pguidEventContext) = 0;
  16. virtual HRESULT STDMETHODCALLTYPE GetMute(BOOL *pbMute) = 0;
  17. virtual HRESULT STDMETHODCALLTYPE GetVolumeStepInfo(UINT *pnStep,UINT *pnStepCount) = 0;
  18. virtual HRESULT STDMETHODCALLTYPE VolumeStepUp(LPCGUID pguidEventContext) = 0;
  19. virtual HRESULT STDMETHODCALLTYPE VolumeStepDown(LPCGUID pguidEventContext) = 0;
  20. virtual HRESULT STDMETHODCALLTYPE QueryHardwareSupport(DWORD *pdwHardwareSupportMask) = 0;
  21. virtual HRESULT STDMETHODCALLTYPE GetVolumeRange(float *pflVolumeMindB,float *pflVolumeMaxdB,float *pflVolumeIncrementdB) = 0;
  22. };
这个IAudioEndpointVolume接口方法很多,不仔细介绍每一个了,只介绍我们需要用到的几个方法,大家可以根据自己的需要,顾名思义找到自己需要用的方法。
  1. /*
  2. 设置音频终端的主音量电;
  3. fLevel:主音量数值级别,这个值范围在0到1之间;
  4. pguidEventContext):此参数指向一个事件上下文的GUID,如果SetMasterVolumeLevelScalar调用更改端点的音量,所有已注册客户IAudioEndpointVolumeCallback接口与端点将接收通知。
  5. */
  6. HRESULT SetMasterVolumeLevelScalar(float fLevel,LPCGUID pguidEventContext);
  7. //获取音频终端的主音量电平;
  8. HRESULT GetMasterVolumeLevelScalar(float *pfLevel);
  9. //设置音频终端是否为静音状态;
  10. HRESULT SetMute(BOOL bMute,LPCGUID pguidEventContext);
  11. //获取音频终端是静音状态;
  12. HRESULT GetMute(BOOL *pbMute);
其余几个参数很简单,看名字就知道什么意思,不作过多介绍。

设置系统扬声器音量代码示例:

  1. float level = 0.5f;//这个值可以跟进相应比例换算所得
  2. hr = m_pRenderEndptVol->SetMasterVolumeLevelScalar(level, NULL);
获取系统扬声器音量代码示例:
  1. float level = 0.0f;
  2. hr = m_pRenderEndptVol->GetMasterVolumeLevelScalar(&level);
注意level这个值一般根据界面滑动条最大值按比例换算所得。
设置系统扬声器静音示例:
hr = m_pRenderSimpleVol->SetMute(TRUE, NULL);

获取系统扬声器静音状态示例: 

  1. BOOL bMute = 0;
  2. hr = m_pRenderSimpleVol->GetMute(&bMute);
这只是简单的几种参数设置,大家可以根据自己的需要来选择不同方法达到自己目的。

6.设置应用程序会话音量
        上面设置的都是系统扬声器的音量,即相应的设置会影响系统上所有软件的音量,下面我们来设置属于应用程序本身的会话音量,所谓会话音量即时这个应用程序本身的音量,设置会话音量的大小只会影响应用程序本身的音量大小,不会影响系统其它程序音量的大小。首先我们要获取IAudioSessionManager接口对象,方法是通过已经获取IMMDevice接口对象来激活IAudioSessionManager接口对象,然后就可以通过IAudioSessionManager接口来获取ISimpleAudioVolume接口对象了,最后通过ISimpleAudioVolume接口对象就可以操作会话音量的大小了。示例代码如下:

  1. //合成器界面
  2. CComPtr<IAudioSessionManager> pSessionManager = NULL;
  3. hr = pIMMDeivce->Activate(IID_IAudioSessionManager, CLSCTX_INPROC_SERVER, NULL, (void **)(&pSessionManager));
  4. if(FAILED(hr)) return;
  5. hr = pSessionManager->GetSimpleAudioVolume(NULL, FALSE, &m_pRenderSimpleVol);

获取到ISimpleAudioVolume接口对象后就可以使用其具有的方法操作具体的功能了,看下这个接口有的方法:

  1. class ISimpleAudioVolume : public IUnknown
  2. {
  3. public:
  4. virtual HRESULT STDMETHODCALLTYPE SetMasterVolume(float fLevel, LPCGUID EventContext) = 0;
  5. virtual HRESULT STDMETHODCALLTYPE GetMasterVolume(float *pfLevel) = 0;
  6. virtual HRESULT STDMETHODCALLTYPE SetMute(const BOOL bMute, LPCGUID EventContext) = 0;
  7. virtual HRESULT STDMETHODCALLTYPE GetMute(BOOL *pbMute) = 0;
  8. };
所有方法和上面IAudioEndpointVolume接口方法基本一样,直接贴代码说明
设置和获取会话音量的大小:
  1. //设置扬声器会话音量大小
  2. float fVol = 0.5f;
  3. hr = m_pRenderSimpleVol->SetMasterVolume(fVol, NULL);
  4. //获取扬声器会话音量大小
  5. float fVol = 0.0f;
  6. hr = m_pRenderSimpleVol->GetMasterVolume(&fVol);
设置和获取会话音量的静音状态:
  1. //设置扬声器会话音量静音状态
  2. BOOL bMute = TRUE;
  3. hr = m_pRenderSimpleVol->SetMute(bMute , NULL);
  4. //获取扬声器静音状态
  5. hr = m_pRenderSimpleVol->GetMute(&bMute);
        扬声器里面的功能设置还有很多方法,介绍只是最基本的方法,大家可以根据自己需要挖掘更深层的设置方法,这一节就先介绍到这里吧,下一节介绍系统麦克风方面一些简单的设置。                                      

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多