wasapi-enum-devices.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. #include "../../obs-internal.h"
  2. #include "wasapi-output.h"
  3. #include <propsys.h>
  4. #ifdef __MINGW32__
  5. #ifdef DEFINE_PROPERTYKEY
  6. #undef DEFINE_PROPERTYKEY
  7. #endif
  8. #define DEFINE_PROPERTYKEY(id, a, b, c, d, e, f, g, h, i, j, k, l) \
  9. const PROPERTYKEY id = {{a, \
  10. b, \
  11. c, \
  12. { \
  13. d, \
  14. e, \
  15. f, \
  16. g, \
  17. h, \
  18. i, \
  19. j, \
  20. k, \
  21. }}, \
  22. l};
  23. DEFINE_PROPERTYKEY(PKEY_Device_FriendlyName, 0xa45c254e, 0xdf1c, 0x4efd, 0x80,
  24. 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0, 14);
  25. #else
  26. #include <functiondiscoverykeys_devpkey.h>
  27. #endif
  28. static bool get_device_info(obs_enum_audio_device_cb cb, void *data,
  29. IMMDeviceCollection *collection, UINT idx)
  30. {
  31. IPropertyStore *store = NULL;
  32. IMMDevice *device = NULL;
  33. PROPVARIANT name_var;
  34. char utf8_name[512];
  35. WCHAR *w_id = NULL;
  36. char utf8_id[512];
  37. bool cont = true;
  38. HRESULT hr;
  39. hr = collection->lpVtbl->Item(collection, idx, &device);
  40. if (FAILED(hr)) {
  41. goto fail;
  42. }
  43. hr = device->lpVtbl->GetId(device, &w_id);
  44. if (FAILED(hr)) {
  45. goto fail;
  46. }
  47. hr = device->lpVtbl->OpenPropertyStore(device, STGM_READ, &store);
  48. if (FAILED(hr)) {
  49. goto fail;
  50. }
  51. PropVariantInit(&name_var);
  52. hr = store->lpVtbl->GetValue(store, &PKEY_Device_FriendlyName,
  53. &name_var);
  54. if (FAILED(hr)) {
  55. goto fail;
  56. }
  57. os_wcs_to_utf8(w_id, 0, utf8_id, 512);
  58. os_wcs_to_utf8(name_var.pwszVal, 0, utf8_name, 512);
  59. cont = cb(data, utf8_name, utf8_id);
  60. PropVariantClear(&name_var);
  61. fail:
  62. safe_release(store);
  63. safe_release(device);
  64. if (w_id)
  65. CoTaskMemFree(w_id);
  66. return cont;
  67. }
  68. void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb, void *data)
  69. {
  70. IMMDeviceEnumerator *enumerator = NULL;
  71. IMMDeviceCollection *collection = NULL;
  72. UINT count;
  73. HRESULT hr;
  74. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
  75. &IID_IMMDeviceEnumerator, &enumerator);
  76. if (FAILED(hr)) {
  77. goto fail;
  78. }
  79. hr = enumerator->lpVtbl->EnumAudioEndpoints(
  80. enumerator, eRender, DEVICE_STATE_ACTIVE, &collection);
  81. if (FAILED(hr)) {
  82. goto fail;
  83. }
  84. hr = collection->lpVtbl->GetCount(collection, &count);
  85. if (FAILED(hr)) {
  86. goto fail;
  87. }
  88. for (UINT i = 0; i < count; i++) {
  89. if (!get_device_info(cb, data, collection, i)) {
  90. break;
  91. }
  92. }
  93. fail:
  94. safe_release(enumerator);
  95. safe_release(collection);
  96. }
  97. static void get_default_id(char **p_id)
  98. {
  99. IMMDeviceEnumerator *immde = NULL;
  100. IMMDevice *device = NULL;
  101. WCHAR *w_id = NULL;
  102. HRESULT hr;
  103. if (*p_id)
  104. return;
  105. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
  106. &IID_IMMDeviceEnumerator, &immde);
  107. if (FAILED(hr)) {
  108. goto fail;
  109. }
  110. hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender, eConsole,
  111. &device);
  112. if (FAILED(hr)) {
  113. goto fail;
  114. }
  115. hr = device->lpVtbl->GetId(device, &w_id);
  116. if (FAILED(hr)) {
  117. goto fail;
  118. }
  119. os_wcs_to_utf8_ptr(w_id, 0, p_id);
  120. fail:
  121. if (!*p_id)
  122. *p_id = bzalloc(1);
  123. if (immde)
  124. immde->lpVtbl->Release(immde);
  125. if (device)
  126. device->lpVtbl->Release(device);
  127. if (w_id)
  128. CoTaskMemFree(w_id);
  129. }
  130. bool devices_match(const char *id1, const char *id2)
  131. {
  132. char *default_id = NULL;
  133. bool match;
  134. if (!id1 || !id2)
  135. return false;
  136. if (strcmp(id1, "default") == 0) {
  137. get_default_id(&default_id);
  138. id1 = default_id;
  139. }
  140. if (strcmp(id2, "default") == 0) {
  141. get_default_id(&default_id);
  142. id2 = default_id;
  143. }
  144. match = strcmp(id1, id2) == 0;
  145. bfree(default_id);
  146. return match;
  147. }