#include "stdafx.h" #include "SpBase.h" #include "volumekeeper.h" #include #include #include #include #include #include #define EXIT_ON_ERROR(x) if (FAILED(x)) {goto Exit;} #define RETURN_ERROR(x) FAILED(x)?false:true class volume_keeper_t : public IAudioEndpointVolumeCallback { private: char m_dev_key[MAX_PATH]; int m_in_dev; ULONG m_lRef; public: IAudioEndpointVolume *m_pAudioEndpointVolume; GUID m_guidContext; float m_kept_value; volume_keeper_t(const char *dev_key, int in_dev, int kept_value) : m_lRef(1), m_kept_value(kept_value/100.0f), m_pAudioEndpointVolume(NULL), m_in_dev(in_dev) { strcpy(m_dev_key, dev_key); } HRESULT Init() { IMMDeviceEnumerator *pEnumerator = NULL; IMMDeviceCollection *pDeviceCollection = NULL; HRESULT hr; hr = CoCreateGuid(&m_guidContext); EXIT_ON_ERROR(hr); hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator); EXIT_ON_ERROR(hr); hr = pEnumerator->EnumAudioEndpoints(m_in_dev ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection); EXIT_ON_ERROR(hr); UINT nCount = 0; hr = pDeviceCollection->GetCount(&nCount); EXIT_ON_ERROR(hr); for (UINT i = 0; i < nCount; ++i) { IMMDevice *pDevice = NULL; hr = pDeviceCollection->Item(i, &pDevice); if (SUCCEEDED(hr)) { char name[260]; IPropertyStore *pPS = NULL; PROPVARIANT value; PropVariantInit(&value); pDevice->OpenPropertyStore(STGM_READ, &pPS); pPS->GetValue(PKEY_Device_FriendlyName, &value); WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0); PropVariantClear(&value); pPS->Release(); if (strstr(name, m_dev_key)) { hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&m_pAudioEndpointVolume); if (SUCCEEDED(hr)) { hr = m_pAudioEndpointVolume->RegisterControlChangeNotify(this); m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext); } pDevice->Release(); break; } else { pDevice->Release(); } } else { break; } } Exit: if (pDeviceCollection) { pDeviceCollection->Release(); } if (pEnumerator) { pEnumerator->Release(); } return hr; } void Term() { if (m_pAudioEndpointVolume) { m_pAudioEndpointVolume->UnregisterControlChangeNotify(this); m_pAudioEndpointVolume->Release(); } } void ChangeValue(int nValue) { m_kept_value=nValue/100.f; } ULONG STDMETHODCALLTYPE AddRef() { return InterlockedIncrement(&m_lRef); } ULONG STDMETHODCALLTYPE Release() { ULONG ulRef = InterlockedDecrement(&m_lRef); if (0 == ulRef) { delete this; } return ulRef; } HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface) { if (IID_IUnknown == riid) { AddRef(); *ppvInterface = (IUnknown*)this; } else if (__uuidof(IAudioEndpointVolumeCallback) == riid) { AddRef(); *ppvInterface = (IAudioEndpointVolumeCallback*)this; } else { *ppvInterface = NULL; return E_NOINTERFACE; } return S_OK; } // Callback method for endpoint-volume-change notifications. HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify) { if (pNotify == NULL) { return E_INVALIDARG; } if (pNotify->guidEventContext != m_guidContext) { if (pNotify->fMasterVolume != m_kept_value) { m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext); } } return S_OK; } }; void *volume_keeper_create(const char *dev_key_name, int in_dev, int kept_value) { if (!dev_key_name) { return NULL; } if (kept_value < 0 || kept_value > 100) { return NULL; } volume_keeper_t *inst = new volume_keeper_t(dev_key_name, in_dev, kept_value); if (SUCCEEDED(inst->Init())) { return inst; } else { inst->Release(); } return NULL; } void volume_keeper_destroy(void *inst) { volume_keeper_t *keeper = (volume_keeper_t*)inst; keeper->Term(); keeper->Release(); } void volume_keeper_change(void *inst,int change_value) { volume_keeper_t *keeper = (volume_keeper_t*)inst; float fCurValue = 0.0; keeper->m_kept_value =(change_value/100.0f); if (keeper->m_kept_value>1) { keeper->m_kept_value = 1; } else if (keeper->m_kept_value<0) { keeper->m_kept_value = 0; } if (NULL != keeper->m_pAudioEndpointVolume){ keeper->m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(keeper->m_kept_value,&keeper->m_guidContext); } } bool get_audiodevice_volumn(void *inst,int*nvalue) { volume_keeper_t *keeper = (volume_keeper_t*)inst; float fValue = 0.0; if (NULL != keeper->m_pAudioEndpointVolume){ keeper->m_pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fValue); } *nvalue = fValue*100; return true; }