libaudiomgr_win.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. #include"libaudiomgr_win.h"
  2. #include <stdlib.h>
  3. #include <string.h>
  4. // Macro that releases a COM object if not NULL.
  5. #define SAFE_RELEASE(p) \
  6. do { \
  7. if ((p)) { \
  8. (p)->Release(); \
  9. (p) = NULL; \
  10. } \
  11. } while (0)
  12. typedef struct tagAUDIO_DEVICE_INFO{
  13. char szDeviceName[MAX_PATH];
  14. char szDeviceID[MAX_PATH];
  15. } AUDIO_DEVICE_INFO, *PAUDIO_DEVICE_INFO;
  16. AudioMgrImpl::AudioMgrImpl(audiomgr_callback_t* pCallback)
  17. {
  18. memcpy(&m_callback, pCallback, sizeof(audiomgr_callback_t));
  19. m_pEnumerator = NULL;
  20. m_builtInAecEnabled = false;
  21. m_dmo = NULL;
  22. m_ptrCaptureCollection = NULL;
  23. m_ptrDeviceIn = NULL;
  24. m_usingInputDeviceIndex = false;
  25. m_inputDeviceIndex = 0;
  26. }
  27. AudioMgrImpl::~AudioMgrImpl()
  28. {
  29. }
  30. int AudioMgrImpl::audio_mgr_destroy()
  31. {
  32. delete this;
  33. return 0;
  34. }
  35. void AudioMgrImpl::audiolog(const char* fmt, ...)
  36. {
  37. if (m_callback.debug) {
  38. va_list arg;
  39. va_start(arg, fmt);
  40. if (*m_callback.debug) {
  41. (*m_callback.debug)(m_callback.user_data, fmt, arg);
  42. }
  43. va_end(arg);
  44. }
  45. }
  46. int AudioMgrImpl::audio_get_device_count(bool binput)
  47. {
  48. UINT uDevCount = 0;
  49. IMMDeviceCollection *pEndpoints = NULL;
  50. HRESULT hr(S_OK);
  51. hr = m_pEnumerator->EnumAudioEndpoints(binput ? eCapture : eRender, DEVICE_STATE_ACTIVE, (IMMDeviceCollection**)&pEndpoints);
  52. if (FAILED(hr)){
  53. SAFE_RELEASE(pEndpoints);
  54. return 0;
  55. }
  56. hr = pEndpoints->GetCount(&uDevCount);
  57. if (FAILED(hr)){
  58. SAFE_RELEASE(pEndpoints);
  59. return 0;
  60. }
  61. SAFE_RELEASE(pEndpoints);
  62. return static_cast<int16_t>(uDevCount);
  63. }
  64. int AudioMgrImpl::audio_get_device_name(char* pstrbuf, size_t ulen, bool binput, unsigned int uindex)
  65. {
  66. int iret = -1;
  67. IMMDeviceCollection *pDeviceCollection = NULL;
  68. HRESULT hr(S_OK);
  69. hr = m_pEnumerator->EnumAudioEndpoints(binput ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  70. if (FAILED(hr)){
  71. SAFE_RELEASE(pDeviceCollection);
  72. return -1;
  73. }
  74. UINT nCount = 0;
  75. hr = pDeviceCollection->GetCount(&nCount);
  76. if (FAILED(hr)){
  77. SAFE_RELEASE(pDeviceCollection);
  78. return -1;
  79. }
  80. if (uindex < nCount) {
  81. IMMDevice *pDevice = NULL;
  82. hr = pDeviceCollection->Item(uindex, &pDevice);
  83. if (SUCCEEDED(hr)) {
  84. IPropertyStore *pPS = NULL;
  85. PROPVARIANT value;
  86. PropVariantInit(&value);
  87. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  88. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  89. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, pstrbuf, ulen - 1, 0, 0);
  90. PropVariantClear(&value);
  91. pPS->Release();
  92. }
  93. }
  94. SAFE_RELEASE(pDeviceCollection);
  95. return iret;
  96. }
  97. int AudioMgrImpl::audio_get_device_id(const char* pstrname, bool binput)
  98. {
  99. int iret = -1;
  100. if (NULL == pstrname){
  101. return iret;
  102. }
  103. IMMDeviceCollection *pDeviceCollection = NULL;
  104. HRESULT hr(S_OK);
  105. hr = m_pEnumerator->EnumAudioEndpoints(binput ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  106. if (FAILED(hr)){
  107. SAFE_RELEASE(pDeviceCollection);
  108. return -1;
  109. }
  110. UINT nCount = 0;
  111. hr = pDeviceCollection->GetCount(&nCount);
  112. if (FAILED(hr)){
  113. SAFE_RELEASE(pDeviceCollection);
  114. return -1;
  115. }
  116. for (UINT index = 0; index < nCount; ++index) {
  117. IMMDevice *pDevice = NULL;
  118. hr = pDeviceCollection->Item(index, &pDevice);
  119. if (SUCCEEDED(hr)) {
  120. char name[MAX_PATH] = {0};
  121. IPropertyStore *pPS = NULL;
  122. PROPVARIANT value;
  123. PropVariantInit(&value);
  124. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  125. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  126. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  127. PropVariantClear(&value);
  128. pPS->Release();
  129. if (strstr(name, pstrname)) {
  130. iret = index;
  131. pDevice->Release();
  132. break;
  133. } else {
  134. pDevice->Release();
  135. }
  136. } else {
  137. break;
  138. }
  139. }
  140. SAFE_RELEASE(pDeviceCollection);
  141. return iret;
  142. }
  143. rvc_audio_device_t* AudioMgrImpl::audio_get_device_infos(bool binput, int index)
  144. {
  145. return NULL;
  146. }
  147. int AudioMgrImpl::audio_get_device_volume(int* ivolume, const char* pstrname, bool binput)
  148. {
  149. int iret = -1;
  150. IMMDeviceCollection *pDeviceCollection = NULL;
  151. IAudioEndpointVolume *pAudioEndpointVolume;
  152. HRESULT hr(S_OK);
  153. hr = m_pEnumerator->EnumAudioEndpoints(binput ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  154. if (FAILED(hr)) {
  155. SAFE_RELEASE(pDeviceCollection);
  156. return -1;
  157. }
  158. UINT nCount = 0;
  159. hr = pDeviceCollection->GetCount(&nCount);
  160. if (FAILED(hr)){
  161. return -1;
  162. }
  163. for (UINT i = 0; i < nCount; ++i) {
  164. IMMDevice *pDevice = NULL;
  165. hr = pDeviceCollection->Item(i, &pDevice);
  166. if (SUCCEEDED(hr)) {
  167. char name[MAX_PATH] = {0};
  168. IPropertyStore *pPS = NULL;
  169. PROPVARIANT value;
  170. PropVariantInit(&value);
  171. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  172. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  173. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  174. PropVariantClear(&value);
  175. pPS->Release();
  176. if (strstr(name, pstrname)) {
  177. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&pAudioEndpointVolume);
  178. if (SUCCEEDED(hr)) {
  179. float fValue = 0.0;
  180. hr = pAudioEndpointVolume->GetMasterVolumeLevelScalar(&fValue);
  181. if (SUCCEEDED(hr)){
  182. *ivolume = static_cast<uint32_t>(fValue*100);
  183. iret = 0;
  184. }
  185. }
  186. pDevice->Release();
  187. break;
  188. } else {
  189. pDevice->Release();
  190. }
  191. } else {
  192. break;
  193. }
  194. }
  195. SAFE_RELEASE(pDeviceCollection);
  196. return iret;
  197. }
  198. int AudioMgrImpl::audio_set_device_volume(int ivolume, const char* pstrname, bool binput)
  199. {
  200. int iret = -1;
  201. IMMDeviceCollection *pDeviceCollection = NULL;
  202. IAudioEndpointVolume *pAudioEndpointVolume;
  203. GUID guidContext;
  204. HRESULT hr(S_OK);
  205. hr = CoCreateGuid(&guidContext);
  206. if (FAILED(hr)){
  207. return -1;
  208. }
  209. hr = m_pEnumerator->EnumAudioEndpoints(binput ? eCapture : eRender, DEVICE_STATE_ACTIVE, &pDeviceCollection);
  210. if (FAILED(hr)){
  211. SAFE_RELEASE(pDeviceCollection);
  212. return -1;
  213. }
  214. UINT nCount = 0;
  215. hr = pDeviceCollection->GetCount(&nCount);
  216. if (FAILED(hr)){
  217. SAFE_RELEASE(pDeviceCollection);
  218. return -1;
  219. }
  220. for (UINT i = 0; i < nCount; ++i) {
  221. IMMDevice *pDevice = NULL;
  222. hr = pDeviceCollection->Item(i, &pDevice);
  223. if (SUCCEEDED(hr)) {
  224. char name[MAX_PATH] = {0};
  225. IPropertyStore *pPS = NULL;
  226. PROPVARIANT value;
  227. PropVariantInit(&value);
  228. pDevice->OpenPropertyStore(STGM_READ, &pPS);
  229. pPS->GetValue(PKEY_Device_FriendlyName, &value);
  230. WideCharToMultiByte(CP_ACP, 0, value.pwszVal, -1, name, sizeof(name)-1, 0, 0);
  231. PropVariantClear(&value);
  232. pPS->Release();
  233. if (strstr(name, pstrname)) {
  234. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_INPROC_SERVER, NULL, (void**)&pAudioEndpointVolume);
  235. if (SUCCEEDED(hr)) {
  236. hr = pAudioEndpointVolume->SetMasterVolumeLevelScalar(ivolume/100.f, &guidContext);
  237. if (SUCCEEDED(hr)){
  238. iret = 0;
  239. }
  240. }
  241. pDevice->Release();
  242. break;
  243. }
  244. else {
  245. pDevice->Release();
  246. }
  247. }
  248. else {
  249. break;
  250. }
  251. }
  252. SAFE_RELEASE(pDeviceCollection);
  253. return iret;
  254. }
  255. int AudioMgrImpl::audio_mgr_initialize()
  256. {
  257. int iret = -1;
  258. CoInitialize(NULL);
  259. HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, __uuidof(IMMDeviceEnumerator), (void**)&m_pEnumerator);
  260. if (!FAILED(hr)){
  261. iret = 0;
  262. }
  263. // DMO initialization for built-in WASAPI AEC.
  264. {
  265. IMediaObject* ptrDMO = NULL;
  266. hr = CoCreateInstance(CLSID_CWMAudioAEC, NULL, CLSCTX_INPROC_SERVER,
  267. IID_IMediaObject, reinterpret_cast<void**>(&ptrDMO));
  268. if (FAILED(hr) || ptrDMO == NULL) {
  269. // Since we check that _dmo is non-NULL in EnableBuiltInAEC(), the
  270. // feature is prevented from being enabled.
  271. m_builtInAecEnabled = false;
  272. //_TraceCOMError(hr);
  273. }
  274. m_dmo = ptrDMO;
  275. SAFE_RELEASE(ptrDMO);
  276. }
  277. return iret;
  278. }
  279. int AudioMgrImpl::set_audio_capture_params(audiocap_param_t* param)
  280. {
  281. int iret = -1;
  282. int index = param->ideviceid;
  283. //UINT nDevices = RecordingDevices();
  284. //if (index < 0 || index >(nDevices - 1)) {
  285. // RTC_LOG(LS_ERROR) << "device index is out of range [0," << (nDevices - 1)
  286. // << "]";
  287. // return -1;
  288. //}
  289. HRESULT hr(S_OK);
  290. assert(m_ptrCaptureCollection != NULL);
  291. // Select an endpoint capture device given the specified index
  292. SAFE_RELEASE(m_ptrDeviceIn);
  293. hr = m_ptrCaptureCollection->Item(index, &m_ptrDeviceIn);
  294. if (FAILED(hr)) {
  295. //_TraceCOMError(hr);
  296. SAFE_RELEASE(m_ptrDeviceIn);
  297. return -1;
  298. }
  299. WCHAR szDeviceName[MAX_PATH] = {0};
  300. const int bufferLen = sizeof(szDeviceName) / sizeof(szDeviceName)[0];
  301. // Get the endpoint device's friendly-name
  302. if (getdevicename(m_ptrDeviceIn, szDeviceName, bufferLen) == 0) {
  303. audiolog("friendly name: %s.", szDeviceName);
  304. }
  305. m_usingInputDeviceIndex = true;
  306. m_inputDeviceIndex = index;
  307. return iret;
  308. }
  309. int AudioMgrImpl::audio_mgr_terminate()
  310. {
  311. int iret = -1;
  312. SAFE_RELEASE(m_pEnumerator);
  313. CoUninitialize();
  314. iret = 0;
  315. return iret;
  316. }
  317. int AudioMgrImpl::stop_audio_capture()
  318. {
  319. return 0;
  320. }
  321. int AudioMgrImpl::start_audio_capture()
  322. {
  323. return 0;
  324. }
  325. int32_t AudioMgrImpl::getlistdevice(EDataFlow dir, int index, IMMDevice** ppDevice)
  326. {
  327. HRESULT hr(S_OK);
  328. IMMDeviceCollection *pCollection = NULL;
  329. hr = m_pEnumerator->EnumAudioEndpoints(
  330. dir,
  331. DEVICE_STATE_ACTIVE, // only active endpoints are OK
  332. &pCollection);
  333. if (FAILED(hr)){
  334. SAFE_RELEASE(pCollection);
  335. return -1;
  336. }
  337. hr = pCollection->Item(index,ppDevice);
  338. if (FAILED(hr)){
  339. SAFE_RELEASE(pCollection);
  340. return -1;
  341. }
  342. return 0;
  343. }
  344. int32_t AudioMgrImpl::getdevicename(IMMDevice* pDevice,
  345. LPWSTR pszBuffer,
  346. int bufferLen)
  347. {
  348. audiolog("%s.", __FUNCTION__);
  349. static const WCHAR szDefault[] = L"<Device not available>";
  350. HRESULT hr = E_FAIL;
  351. IPropertyStore* pProps = NULL;
  352. PROPVARIANT varName;
  353. assert(pszBuffer != NULL);
  354. assert(bufferLen > 0);
  355. if (pDevice != NULL) {
  356. hr = pDevice->OpenPropertyStore(STGM_READ, &pProps);
  357. if (FAILED(hr)) {
  358. audiolog("IMMDevice::OpenPropertyStore failed, hr = 0x%08x.",hr);
  359. }
  360. }
  361. // Initialize container for property value.
  362. PropVariantInit(&varName);
  363. if (SUCCEEDED(hr)) {
  364. // Get the endpoint device's friendly-name property.
  365. hr = pProps->GetValue(PKEY_Device_FriendlyName, &varName);
  366. if (FAILED(hr)) {
  367. audiolog("IPropertyStore::GetValue failed, hr = 0x%08x", hr);
  368. }
  369. }
  370. if ((SUCCEEDED(hr)) && (VT_EMPTY == varName.vt)) {
  371. hr = E_FAIL;
  372. audiolog("IPropertyStore::GetValue returned no value, hr = 0x%08x", hr);
  373. }
  374. if ((SUCCEEDED(hr)) && (VT_LPWSTR != varName.vt)) {
  375. // The returned value is not a wide null terminated string.
  376. hr = E_UNEXPECTED;
  377. audiolog("IPropertyStore::GetValue returned unexpected type, hr = 0x%08x", hr);
  378. }
  379. if (SUCCEEDED(hr) && (varName.pwszVal != NULL)) {
  380. // Copy the valid device name to the provided ouput buffer.
  381. wcsncpy_s(pszBuffer, bufferLen, varName.pwszVal, _TRUNCATE);
  382. }
  383. else {
  384. // Failed to find the device name.
  385. wcsncpy_s(pszBuffer, bufferLen, szDefault, _TRUNCATE);
  386. }
  387. PropVariantClear(&varName);
  388. SAFE_RELEASE(pProps);
  389. return 0;
  390. }