windows monitor speaker, microphone mute, volume event

I. Introduction

I don't want to write a preface, but I just want to record the demos that are usually used in operating system-related tests, sort them out and send them out. The specific usage scenarios are treated according to the needs.

This blog only records how to monitor the mute and volume events of the system speaker and microphone under windows, and I will sort out the mac os later. Because the needs are different, it is only used as a reference.

directly on the code

| Version statement: Mr. Shanhe, without the permission of the blogger, reprinting is prohibited

Two, realize

1. Header file

#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. Source files

#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;
	}
}

Guess you like

Origin blog.csdn.net/qq_42956179/article/details/126232964