volumekeeper.cpp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  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. IAudioEndpointVolume *m_pAudioEndpointVolume;
  15. //float fLevelMinDB;
  16. //float fLevelMaxDB;
  17. //float fLevelIncDB;
  18. float m_kept_value;
  19. GUID m_guidContext;
  20. char m_dev_key[260];
  21. int m_in_dev;
  22. ULONG m_lRef;
  23. public:
  24. 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)
  25. {
  26. strcpy(m_dev_key, dev_key);
  27. }
  28. HRESULT Init()
  29. {
  30. IMMDeviceEnumerator *pEnumerator = NULL;
  31. IMMDeviceCollection *pDeviceCollection = NULL;
  32. HRESULT hr;
  33. hr = CoCreateGuid(&m_guidContext);
  34. EXIT_ON_ERROR(hr);
  35. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
  36. EXIT_ON_ERROR(hr);
  37. hr = pEnumerator->EnumAudioEndpoints(m_in_dev ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  38. EXIT_ON_ERROR(hr);
  39. UINT nCount = 0;
  40. hr = pDeviceCollection->GetCount(&nCount);
  41. EXIT_ON_ERROR(hr);
  42. for (UINT i = 0; i < nCount; ++i) {
  43. IMMDevice *pDevice = NULL;
  44. hr = pDeviceCollection->Item(i, &pDevice);
  45. if (SUCCEEDED(hr)) {
  46. char name[260];
  47. IPropertyStore *pPS = NULL;
  48. PROPVARIANT value;
  49. PropVariantInit(&value);
  50. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  51. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  52. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  53. PropVariantClear(&value);
  54. pPS->Release();
  55. //if (strstr(name, m_dev_key)) { // edit by ly at 2017/02/24
  56. if (!strcmp(name, m_dev_key)) {
  57. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&m_pAudioEndpointVolume);
  58. if (SUCCEEDED(hr)) {
  59. hr = m_pAudioEndpointVolume->RegisterControlChangeNotify(this);
  60. m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext);
  61. Dbg("[dbg] OK to set volume of %s with %d.", name, (int)m_kept_value);
  62. }
  63. pDevice->Release();
  64. break;
  65. } else {
  66. pDevice->Release();
  67. }
  68. } else {
  69. break;
  70. }
  71. }
  72. Exit:
  73. if (pDeviceCollection) {
  74. pDeviceCollection->Release();
  75. }
  76. if (pEnumerator) {
  77. pEnumerator->Release();
  78. }
  79. return hr;
  80. }
  81. void Term()
  82. {
  83. if (m_pAudioEndpointVolume) {
  84. m_pAudioEndpointVolume->UnregisterControlChangeNotify(this);
  85. m_pAudioEndpointVolume->Release();
  86. }
  87. }
  88. void ChangeValue(int nValue)
  89. {
  90. m_kept_value=nValue/100.f;
  91. }
  92. ULONG STDMETHODCALLTYPE AddRef()
  93. {
  94. return InterlockedIncrement(&m_lRef);
  95. }
  96. ULONG STDMETHODCALLTYPE Release()
  97. {
  98. ULONG ulRef = InterlockedDecrement(&m_lRef);
  99. if (0 == ulRef) {
  100. delete this;
  101. }
  102. return ulRef;
  103. }
  104. HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, VOID **ppvInterface)
  105. {
  106. if (IID_IUnknown == riid) {
  107. AddRef();
  108. *ppvInterface = (IUnknown*)this;
  109. } else if (__uuidof(IAudioEndpointVolumeCallback) == riid) {
  110. AddRef();
  111. *ppvInterface = (IAudioEndpointVolumeCallback*)this;
  112. } else {
  113. *ppvInterface = NULL;
  114. return E_NOINTERFACE;
  115. }
  116. return S_OK;
  117. }
  118. // Callback method for endpoint-volume-change notifications.
  119. HRESULT STDMETHODCALLTYPE OnNotify(PAUDIO_VOLUME_NOTIFICATION_DATA pNotify)
  120. {
  121. if (pNotify == NULL) {
  122. return E_INVALIDARG;
  123. }
  124. if (pNotify->guidEventContext != m_guidContext) {
  125. //Dbg("volume notify calblack!");
  126. if (pNotify->fMasterVolume != m_kept_value) {
  127. //Dbg("volumechange notify, pNotify->fMasterVolume:%f", pNotify->fMasterVolume);
  128. m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(m_kept_value, &m_guidContext);
  129. }
  130. }
  131. return S_OK;
  132. }
  133. };
  134. void *volume_keeper_create(const char *dev_key_name, int in_dev, int kept_value)
  135. {
  136. //if (!dev_key_name)
  137. if(!dev_key_name || strlen(dev_key_name) <= 1) // edit by ly at 2017/02/24
  138. return NULL;
  139. if (kept_value < 0 || kept_value > 100)
  140. return NULL;
  141. volume_keeper_t *inst = new volume_keeper_t(dev_key_name, in_dev, kept_value);
  142. if (SUCCEEDED(inst->Init())) {
  143. return inst;
  144. } else {
  145. inst->Release();
  146. }
  147. return NULL;
  148. }
  149. void volume_keeper_destroy(void *inst)
  150. {
  151. volume_keeper_t *keeper = (volume_keeper_t*)inst;
  152. keeper->Term();
  153. keeper->Release();
  154. }
  155. void volume_keeper_change(void *inst,int change_value)
  156. {
  157. volume_keeper_t *keeper = (volume_keeper_t*)inst;
  158. keeper->ChangeValue(change_value);
  159. }
  160. //ÒôÁ¿ÐÞ¸Ä
  161. bool volume_change(const char *dev_key_name, int in_dev,float change_value)
  162. {
  163. if (!dev_key_name)
  164. return false;
  165. if (change_value < 0|| change_value > 100)
  166. return false;
  167. IAudioEndpointVolume *m_pAudioEndpointVolume;
  168. GUID m_guidContext;
  169. IMMDeviceEnumerator *pEnumerator = NULL;
  170. IMMDeviceCollection *pDeviceCollection = NULL;
  171. HRESULT hr;
  172. hr = CoCreateGuid(&m_guidContext);
  173. EXIT_ON_ERROR(hr);
  174. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
  175. EXIT_ON_ERROR(hr);
  176. hr = pEnumerator->EnumAudioEndpoints(in_dev ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  177. EXIT_ON_ERROR(hr);
  178. UINT nCount = 0;
  179. hr = pDeviceCollection->GetCount(&nCount);
  180. EXIT_ON_ERROR(hr);
  181. for (UINT i = 0; i < nCount; ++i)
  182. {
  183. IMMDevice *pDevice = NULL;
  184. hr = pDeviceCollection->Item(i, &pDevice);
  185. if (SUCCEEDED(hr))
  186. {
  187. char name[260];
  188. IPropertyStore *pPS = NULL;
  189. PROPVARIANT value;
  190. PropVariantInit(&value);
  191. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  192. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  193. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  194. PropVariantClear(&value);
  195. pPS->Release();
  196. if (strstr(name, dev_key_name))
  197. {
  198. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&m_pAudioEndpointVolume);
  199. float fCurValue = 0.0;
  200. m_pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fCurValue);
  201. fCurValue =(change_value/100.0f);
  202. if (fCurValue>1)
  203. {
  204. fCurValue = 1;
  205. }
  206. else if (fCurValue<0)
  207. {
  208. fCurValue = 0;
  209. }
  210. m_pAudioEndpointVolume->SetMasterVolumeLevelScalar(fCurValue, &m_guidContext);
  211. pDevice->Release();
  212. m_pAudioEndpointVolume->Release();
  213. break;
  214. }
  215. else
  216. {
  217. pDevice->Release();
  218. }
  219. }
  220. else
  221. {
  222. break;
  223. }
  224. }
  225. Exit:
  226. if (pDeviceCollection)
  227. {
  228. pDeviceCollection->Release();
  229. }
  230. if (pEnumerator)
  231. {
  232. pEnumerator->Release();
  233. }
  234. return RETURN_ERROR(hr);
  235. }
  236. bool get_audiodevice_volumn(const char *dev_key_name, int in_dev,float*fCurValue)
  237. {
  238. if (!dev_key_name)
  239. return false;
  240. IAudioEndpointVolume *m_pAudioEndpointVolume;
  241. GUID m_guidContext;
  242. IMMDeviceEnumerator *pEnumerator = NULL;
  243. IMMDeviceCollection *pDeviceCollection = NULL;
  244. HRESULT hr;
  245. hr = CoCreateGuid(&m_guidContext);
  246. EXIT_ON_ERROR(hr);
  247. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&pEnumerator);
  248. EXIT_ON_ERROR(hr);
  249. hr = pEnumerator->EnumAudioEndpoints(in_dev ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  250. EXIT_ON_ERROR(hr);
  251. UINT nCount = 0;
  252. hr = pDeviceCollection->GetCount(&nCount);
  253. EXIT_ON_ERROR(hr);
  254. for (UINT i = 0; i < nCount; ++i)
  255. {
  256. IMMDevice *pDevice = NULL;
  257. hr = pDeviceCollection->Item(i, &pDevice);
  258. if (SUCCEEDED(hr))
  259. {
  260. char name[260];
  261. IPropertyStore *pPS = NULL;
  262. PROPVARIANT value;
  263. PropVariantInit(&value);
  264. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  265. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  266. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  267. PropVariantClear(&value);
  268. pPS->Release();
  269. if (strstr(name, dev_key_name))
  270. {
  271. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&m_pAudioEndpointVolume);
  272. m_pAudioEndpointVolume->GetMasterVolumeLevelScalar(fCurValue);
  273. pDevice->Release();
  274. m_pAudioEndpointVolume->Release();
  275. break;
  276. }
  277. else
  278. {
  279. pDevice->Release();
  280. }
  281. }
  282. else
  283. {
  284. break;
  285. }
  286. }
  287. Exit:
  288. if (pDeviceCollection)
  289. {
  290. pDeviceCollection->Release();
  291. }
  292. if (pEnumerator)
  293. {
  294. pEnumerator->Release();
  295. }
  296. return RETURN_ERROR(hr);
  297. }