windows监听扬声器、麦克风静音、音量事件

一、前言

不想写前言的,就是想记录一下平常在做和操作系统相关的测试时用的demo,整理一下发出来,具体使用场景根据需求具体对待。

该博客只是记录了在windows下如何监听系统扬声器和麦克风静音、音量的事件,过会再整理一下mac os的。因为需求不同,只用作借鉴。

直接上代码

|版本声明:山河君,未经博主允许,禁止转载

二、实现

1.头文件

#ifndef AUDIO_DEVICE_MOITOR_WIN_
#define AUDIO_DEVICE_MOITOR_WIN_

#include <initguid.h>
#include <windows.h>
#include <commctrl.h>
#include <mmdeviceapi.h>
#include <endpointvolume.h>
#include <cfgmgr32.h> 
#include <audiopolicy.h>
#include <mutex>
#include <string>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <functiondiscoverykeys.h>
#include <algorithm>
#include <setupapi.h>

#pragma comment (lib, "setupapi.lib")
#pragma comment(lib, "avrt.lib")


#define MIC_SYS_MUTE_CHANGE_EVENTS			0x1001
#define MIC_SYS_VOLUME_CHANGE_EVENTS		0x1002

#define SPEAKER_SYS_MUTE_CHANGE_EVENTS		0x2001
#define SPEAKER_SYS_VOLUME_CHANGE_EVENTS	0x2002


namespace webrtc {
    
    


	class AudioDeviceMonitorBase
	{
    
    
	public:
		typedef std::function<void(int, int)> DevEventFun;
		virtual ~AudioDeviceMonitorBase() {
    
    };

	public:
		virtual void SetDeviceEventFuntion(DevEventFun pDevEventFun) = 0;
		virtual bool CreateMicrophoneMonitor(int nIndex) = 0;
		virtual bool CreateSpeakerMonitor(int Index) = 0;
		virtual bool RemoveMoitorMicrophone() = 0;
		virtual bool RemoveMoitorSpeaker() = 0;
	};

#ifndef SAFE_RELEASE
#define SAFE_RELEASE(p) \
  if ((p)) {
      
                  \
    (p)->Release();     \
    (p) = NULL;         \
  }
#endif

	class AudioDeviceMoitor : public AudioDeviceMonitorBase, public IAudioEndpointVolumeCallback
	{
    
    

	public:
		static AudioDeviceMoitor* GetInstance();
		virtual ~AudioDeviceMoitor();

	public:
		virtual void SetDeviceEventFuntion(DevEventFun pDevEventFun) override;
		virtual bool CreateMicrophoneMonitor(int nIndex) override;
		virtual bool CreateSpeakerMonitor(int nIndex) override;
		virtual bool RemoveMoitorMicrophone() override;
		virtual bool RemoveMoitorSpeaker() override;

	public:
		virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID** ppvInterface) override;
		virtual ULONG STDMETHODCALLTYPE AddRef(void) override;
		virtual ULONG STDMETHODCALLTYPE Release(void) override;
		virtual HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) override;

	private:
		std::string UTF8Encode(const std::wstring &strInput);
		void SendEvent(int event, int value);
		LPWSTR GetGuid(int index, EDataFlow eDataFlow);

	private:
		AudioDeviceMoitor();
		static AudioDeviceMoitor* m_pInstance;

	private:
		bool						m_bMicMuteStatus = false;
		bool						m_bSpeakerMuteStatus = false;
		uint16_t					m_uMicrophoneIndex = 0;
		uint16_t					m_uSpeakerIndex = 0;
		uint32_t					m_uMicVolume = 0;
		uint32_t					m_uSpeakerVolume = 0;
		ULONG						m_uRef;
		IMMDeviceEnumerator*		m_pDeviceEnum = nullptr;
		IMMDevice*					m_pMicrophoneMMDev = nullptr;
		IMMDevice*					m_pSpeakerMMDev = nullptr;
		IAudioEndpointVolume*		m_pMicEndpointVolume = nullptr;
		IAudioEndpointVolume*		m_pSpeakerEndpointVolume = nullptr;
		DevEventFun					m_pDevEventFun = nullptr;
		std::mutex					m_DevEventMutex;
	};
} //namespace webrtc

#endif

2.源文件

#include "audio_device_moitor_win.h"
#include <assert.h>

namespace webrtc
{
    
    
	AudioDeviceMoitor* AudioDeviceMoitor::m_pInstance = nullptr;

	AudioDeviceMoitor* AudioDeviceMoitor::GetInstance()
	{
    
    
		if (m_pInstance == nullptr)
		{
    
    
			m_pInstance = new AudioDeviceMoitor();
		}

		return m_pInstance;
	}

	AudioDeviceMoitor::AudioDeviceMoitor()
	{
    
    
		CoInitializeEx(nullptr, COINIT_MULTITHREADED);
		HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr, CLSCTX_INPROC_SERVER,
			__uuidof(IMMDeviceEnumerator), (LPVOID *)&m_pDeviceEnum);
		if (FAILED(hr) || nullptr == m_pDeviceEnum)
		{
    
    
			assert(NULL != m_pDeviceEnum);
		}

		m_uRef = 1;
	}

	AudioDeviceMoitor::~AudioDeviceMoitor()
	{
    
    
		RemoveMoitorMicrophone();
		CoUninitialize();
		m_pInstance = nullptr;
		m_pDeviceEnum = nullptr;
	}

	void AudioDeviceMoitor::SetDeviceEventFuntion(DevEventFun pDevEventFun)
	{
    
    
		std::lock_guard<std::mutex> lockGuard(m_DevEventMutex);
		m_pDevEventFun = pDevEventFun;
	}

	bool AudioDeviceMoitor::CreateMicrophoneMonitor(int nIndex)
	{
    
    
		RemoveMoitorMicrophone();

		LPWSTR wpGuid = GetGuid(nIndex, EDataFlow::eCapture);
		if (wpGuid == nullptr)
		{
    
    
			SAFE_RELEASE(m_pMicrophoneMMDev);
			return false;
		}

		int32_t nRet = 0;
		SAFE_RELEASE(m_pMicEndpointVolume);
		nRet = m_pMicrophoneMMDev->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL,
			reinterpret_cast<void**>(&m_pMicEndpointVolume));
		if (nRet != 0 || m_pMicEndpointVolume == NULL)
		{
    
    
			return false;
		}

		m_pMicEndpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)this);
		return true;
	}

	bool AudioDeviceMoitor::CreateSpeakerMonitor(int nIndex)
	{
    
    
		RemoveMoitorSpeaker();
		LPWSTR wpGuid = GetGuid(nIndex, EDataFlow::eRender);
		if (wpGuid == nullptr)
		{
    
    
			SAFE_RELEASE(m_pSpeakerMMDev);
			return false;
		}

		HRESULT hr = m_pSpeakerMMDev->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&m_pSpeakerEndpointVolume);
		if (FAILED(hr) || nullptr == m_pSpeakerEndpointVolume)
		{
    
    
			return false;
		}
		m_pSpeakerEndpointVolume->RegisterControlChangeNotify((IAudioEndpointVolumeCallback*)this);
		return true;
	}

	bool AudioDeviceMoitor::RemoveMoitorMicrophone()
	{
    
    
		if (m_pMicEndpointVolume)
			m_pMicEndpointVolume->UnregisterControlChangeNotify(this);

		SAFE_RELEASE(m_pMicEndpointVolume);
		SAFE_RELEASE(m_pMicrophoneMMDev);
		return true;
	}

	bool AudioDeviceMoitor::RemoveMoitorSpeaker()
	{
    
    
		if (m_pSpeakerEndpointVolume)
			m_pSpeakerEndpointVolume->UnregisterControlChangeNotify(this);

		SAFE_RELEASE(m_pSpeakerEndpointVolume);
		SAFE_RELEASE(m_pSpeakerMMDev);
		return true;
	}

	void AudioDeviceMoitor::SendEvent(int event, int value)
	{
    
    
		std::lock_guard<std::mutex> lockGuard(m_DevEventMutex);
		if (m_pDevEventFun != nullptr)
		{
    
    
			m_pDevEventFun(event, value);
		}
	}

	LPWSTR AudioDeviceMoitor::GetGuid(int index, EDataFlow eDataFlow)
	{
    
    
		HRESULT hr = S_OK;
		PROPVARIANT varValue;
		LPWSTR pwGuid = nullptr;
		IMMDevice* pDevice = nullptr; 
		IPropertyStore* pProperties = nullptr;
		IMMDeviceCollection  *pCollection = nullptr;
		
		hr = m_pDeviceEnum->EnumAudioEndpoints(eDataFlow, DEVICE_STATE_ACTIVE, &pCollection);
		if (S_OK != hr || nullptr == pCollection)
		{
    
    
			return nullptr;
		}

		hr = pCollection->Item(index, &pDevice);
		if (S_OK != hr || nullptr == pDevice)
		{
    
    
			pCollection->Release();
			return nullptr;
		}

		PropVariantInit(&varValue);
		hr = pDevice->OpenPropertyStore(STGM_READ, &pProperties);
		if (S_OK != hr || nullptr == pProperties)
		{
    
    
			pDevice->Release();
			pCollection->Release();
			return nullptr;
		}
		pProperties->GetValue(PKEY_Device_FriendlyName, &varValue);
		PropVariantClear(&varValue);

		pProperties->GetValue(PKEY_AudioEndpoint_GUID, &varValue);
		pwGuid = varValue.pwszVal;
		PropVariantClear(&varValue);
		pProperties->Release();
		pCollection->Release();

		if (eDataFlow == EDataFlow::eCapture)
		{
    
    
			m_pMicrophoneMMDev = pDevice;
		}
		else if (eDataFlow == EDataFlow::eRender)
		{
    
    
			m_pSpeakerMMDev = pDevice;
		}

		return pwGuid;
	}

	HRESULT STDMETHODCALLTYPE AudioDeviceMoitor::QueryInterface(REFIID riid, VOID** ppvInterface) {
    
    
		if (IID_IUnknown == riid)
		{
    
    
			AddRef();
			*ppvInterface = this;
		}
		else if (__uuidof(IMMNotificationClient) == riid)
		{
    
    
			AddRef();
			*ppvInterface = (IMMNotificationClient*)this;
		}
		else if (__uuidof(IAudioEndpointVolumeCallback) == riid)
		{
    
    
			AddRef();
			*ppvInterface = (IAudioEndpointVolumeCallback*)this;
		}
		else if (__uuidof(IAudioSessionEvents) == riid)
		{
    
    
			AddRef();
			*ppvInterface = (IAudioSessionEvents*)this;
		}
		else
		{
    
    
			*ppvInterface = nullptr;
			return E_NOINTERFACE;
		}
		return S_OK;
	}

	ULONG STDMETHODCALLTYPE AudioDeviceMoitor::AddRef(void) {
    
    
		return InterlockedIncrement(&m_uRef);
	}

	ULONG STDMETHODCALLTYPE AudioDeviceMoitor::Release(void) {
    
    
		ULONG uRef = InterlockedDecrement(&m_uRef);
		if (0 == m_uRef)
		{
    
    
			delete this;
		}
		return uRef;
	}

	HRESULT STDMETHODCALLTYPE AudioDeviceMoitor::OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) {
    
    
		if (pNotify == NULL) {
    
    
			return E_INVALIDARG;
		}


		//当有扬声器或者是麦克风发生了静音、音量改变,就会调用到这里
		//我这里不写代码的原因是因为同时监听了扬声器和麦克风,方案1:可以通过guid进行检查,这里就不写了
		//方案2:再编写主动调用扬声器或者麦克风静音的方法

		return S_OK;
	}

	std::string AudioDeviceMoitor::UTF8Encode(const std::wstring &strInput)
	{
    
    
		std::string strOutput;
		LPSTR pstrRes = nullptr;

		int nLen = ::WideCharToMultiByte(CP_UTF8, 0, strInput.c_str(), strInput.size(), 0, 0, NULL, NULL);
		if (nLen > 0)
		{
    
    
			pstrRes = new CHAR[nLen + 1];
			memset(pstrRes, 0, nLen + 1);
		}
		else
		{
    
    
			return "";
		}

		::WideCharToMultiByte(CP_UTF8, 0, strInput.c_str(), strInput.size(), pstrRes, nLen, NULL, NULL);
		pstrRes[nLen] = 0;
		strOutput = pstrRes;
		delete[]pstrRes;

		return strOutput;
	}
}

猜你喜欢

转载自blog.csdn.net/qq_42956179/article/details/126232964