volumekeeper.cpp 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #include "stdafx.h"
  2. #include "SpBase.h"
  3. #include "volumekeeper.h"
  4. #include <audioclient.h>
  5. #include <MMDeviceApi.h>
  6. #include <AudioEngineEndPoint.h>
  7. #include <DeviceTopology.h>
  8. #include <EndpointVolume.h>
  9. #include <functiondiscoverykeys.h>
  10. #define EXIT_ON_ERROR(x) if (FAILED(x)) {goto Exit;}
  11. #define RETURN_ERROR(x) FAILED(x)?false:true
  12. class volume_keeper_t : public IAudioEndpointVolumeCallback
  13. {
  14. private:
  15. char m_dev_key[MAX_PATH];
  16. int m_in_dev;
  17. ULONG m_lRef;
  18. public:
  19. IAudioEndpointVolume *m_pAudioEndpointVolume;
  20. GUID m_guidContext;
  21. float m_kept_value;
  22. 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)
  23. {
  24. strcpy(m_dev_key, dev_key);
  25. }
  26. HRESULT Init()
  27. {
  28. IMMDeviceEnumerator *pEnumerator = NULL;
  29. IMMDeviceCollection *pDeviceCollection = NULL;
  30. HRESULT hr;
  31. hr = CoCreateGuid(&m_guidContext);
  32. EXIT_ON_ERROR(hr);
  33. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
  34. EXIT_ON_ERROR(hr);
  35. hr = pEnumerator->EnumAudioEndpoints(m_in_dev ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  36. EXIT_ON_ERROR(hr);
  37. UINT nCount = 0;
  38. hr = pDeviceCollection->GetCount(&nCount);
  39. EXIT_ON_ERROR(hr);
  40. for (UINT i = 0; i < nCount; ++i) {
  41. IMMDevice *pDevice = NULL;
  42. hr = pDeviceCollection->Item(i, &pDevice);
  43. if (SUCCEEDED(hr)) {
  44. char name[260];
  45. IPropertyStore *pPS = NULL;
  46. PROPVARIANT value;
  47. PropVariantInit(&value);
  48. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  49. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  50. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  51. PropVariantClear(&value);
  52. pPS->Release();
  53. if (strstr(name, m_dev_key)) {
  54. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&m_pAudioEndpointVolume);
  55. if (SUCCEEDED(hr)) {
  56. hr = m_pAudioEndpointVolume->RegisterControlChangeNotify(this);
  57. m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext);
  58. }
  59. pDevice->Release();
  60. break;
  61. } else {
  62. pDevice->Release();
  63. }
  64. } else {
  65. break;
  66. }
  67. }
  68. Exit:
  69. if (pDeviceCollection) {
  70. pDeviceCollection->Release();
  71. }
  72. if (pEnumerator) {
  73. pEnumerator->Release();
  74. }
  75. return hr;
  76. }
  77. void Term()
  78. {
  79. if (m_pAudioEndpointVolume) {
  80. m_pAudioEndpointVolume->UnregisterControlChangeNotify(this);
  81. m_pAudioEndpointVolume->Release();
  82. }
  83. }
  84. void ChangeValue(int nValue)
  85. {
  86. m_kept_value=nValue/100.f;
  87. }
  88. ULONG STDMETHODCALLTYPE AddRef()
  89. {
  90. return InterlockedIncrement(&m_lRef);
  91. }
  92. ULONG STDMETHODCALLTYPE Release()
  93. {
  94. ULONG ulRef = InterlockedDecrement(&m_lRef);
  95. if (0 == ulRef) {
  96. delete this;
  97. }
  98. return ulRef;
  99. }
  100. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface)
  101. {
  102. if (IID_IUnknown == riid) {
  103. AddRef();
  104. *ppvInterface = (IUnknown*)this;
  105. } else if (__uuidof(IAudioEndpointVolumeCallback) == riid) {
  106. AddRef();
  107. *ppvInterface = (IAudioEndpointVolumeCallback*)this;
  108. } else {
  109. *ppvInterface = NULL;
  110. return E_NOINTERFACE;
  111. }
  112. return S_OK;
  113. }
  114. // Callback method for endpoint-volume-change notifications.
  115. HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify)
  116. {
  117. if (pNotify == NULL) {
  118. return E_INVALIDARG;
  119. }
  120. if (pNotify->guidEventContext != m_guidContext) {
  121. if (pNotify->fMasterVolume != m_kept_value) {
  122. m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext);
  123. }
  124. }
  125. return S_OK;
  126. }
  127. };
  128. void *volume_keeper_create(const char *dev_key_name, int in_dev, int kept_value)
  129. {
  130. if (!dev_key_name) {
  131. return NULL;
  132. }
  133. if (kept_value < 0 || kept_value > 100) {
  134. return NULL;
  135. }
  136. volume_keeper_t *inst = new volume_keeper_t(dev_key_name, in_dev, kept_value);
  137. if (SUCCEEDED(inst->Init()))
  138. {
  139. return inst;
  140. }
  141. else
  142. {
  143. inst->Release();
  144. }
  145. return NULL;
  146. }
  147. void volume_keeper_destroy(void *inst)
  148. {
  149. volume_keeper_t *keeper = (volume_keeper_t*)inst;
  150. keeper->Term();
  151. keeper->Release();
  152. }
  153. void volume_keeper_change(void *inst,int change_value)
  154. {
  155. volume_keeper_t *keeper = (volume_keeper_t*)inst;
  156. float fCurValue = 0.0;
  157. keeper->m_kept_value =(change_value/100.0f);
  158. if (keeper->m_kept_value>1)
  159. {
  160. keeper->m_kept_value = 1;
  161. }
  162. else if (keeper->m_kept_value<0)
  163. {
  164. keeper->m_kept_value = 0;
  165. }
  166. if (NULL != keeper->m_pAudioEndpointVolume){
  167. keeper->m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(keeper->m_kept_value,&keeper->m_guidContext);
  168. }
  169. }
  170. bool get_audiodevice_volumn(void *inst,int*nvalue)
  171. {
  172. volume_keeper_t *keeper = (volume_keeper_t*)inst;
  173. float fValue = 0.0;
  174. if (NULL != keeper->m_pAudioEndpointVolume){
  175. keeper->m_pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fValue);
  176. }
  177. *nvalue = fValue*100;
  178. return true;
  179. }