1
0

wasapi-enum-devices.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. fail:
  61. safe_release(store);
  62. safe_release(device);
  63. if (w_id)
  64. CoTaskMemFree(w_id);
  65. return cont;
  66. }
  67. void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb, void *data)
  68. {
  69. IMMDeviceEnumerator *enumerator = NULL;
  70. IMMDeviceCollection *collection = NULL;
  71. UINT count;
  72. HRESULT hr;
  73. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
  74. &IID_IMMDeviceEnumerator, &enumerator);
  75. if (FAILED(hr)) {
  76. goto fail;
  77. }
  78. hr = enumerator->lpVtbl->EnumAudioEndpoints(
  79. enumerator, eRender, DEVICE_STATE_ACTIVE, &collection);
  80. if (FAILED(hr)) {
  81. goto fail;
  82. }
  83. hr = collection->lpVtbl->GetCount(collection, &count);
  84. if (FAILED(hr)) {
  85. goto fail;
  86. }
  87. for (UINT i = 0; i < count; i++) {
  88. if (!get_device_info(cb, data, collection, i)) {
  89. break;
  90. }
  91. }
  92. fail:
  93. safe_release(enumerator);
  94. safe_release(collection);
  95. }
  96. static void get_default_id(char **p_id)
  97. {
  98. IMMDeviceEnumerator *immde = NULL;
  99. IMMDevice *device = NULL;
  100. WCHAR *w_id = NULL;
  101. HRESULT hr;
  102. if (*p_id)
  103. return;
  104. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL,
  105. &IID_IMMDeviceEnumerator, &immde);
  106. if (FAILED(hr)) {
  107. goto fail;
  108. }
  109. hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender, eConsole,
  110. &device);
  111. if (FAILED(hr)) {
  112. goto fail;
  113. }
  114. hr = device->lpVtbl->GetId(device, &w_id);
  115. if (FAILED(hr)) {
  116. goto fail;
  117. }
  118. os_wcs_to_utf8_ptr(w_id, 0, p_id);
  119. fail:
  120. if (!*p_id)
  121. *p_id = bzalloc(1);
  122. if (immde)
  123. immde->lpVtbl->Release(immde);
  124. if (device)
  125. device->lpVtbl->Release(device);
  126. if (w_id)
  127. CoTaskMemFree(w_id);
  128. }
  129. bool devices_match(const char *id1, const char *id2)
  130. {
  131. char *default_id = NULL;
  132. bool match;
  133. if (!id1 || !id2)
  134. return false;
  135. if (strcmp(id1, "default") == 0) {
  136. get_default_id(&default_id);
  137. id1 = default_id;
  138. }
  139. if (strcmp(id2, "default") == 0) {
  140. get_default_id(&default_id);
  141. id2 = default_id;
  142. }
  143. match = strcmp(id1, id2) == 0;
  144. bfree(default_id);
  145. return match;
  146. }