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


    一、前言

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

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

    直接上代码

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

    二、实现

    1.头文件

    #ifndef AUDIO_DEVICE_MOITOR_WIN_
    #define AUDIO_DEVICE_MOITOR_WIN_
    
    #include 
    #include 
    #include 
    #include 
    #include 
    #include  
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    #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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103

    2.源文件

    #include "audio_device_moitor_win.h"
    #include 
    
    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;
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
  • 相关阅读:
    java-php-python-ssm水星家纺网站计算机毕业设计
    c++ 继承与多态
    ai智工作室22级第三次训练赛
    Redis数据结构的奇妙世界:一窥底层存储机制【redis第一部分】
    Redis 单线程模型 精讲
    AntX6 DAG拖拽流程图:从0到1实现流程图05-连接桩篇
    程序员的民宿情结
    ORB-SLAM3从理论到代码实现(一):Optimizer单帧优化
    ✔ ★【备战实习(面经+项目+算法)】 10.15学习时间表
    leetcode 332. 重新安排行程
  • 原文地址:https://blog.csdn.net/qq_42956179/article/details/126232964