wasapi-enum-devices.c 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  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, 0x20, 0x67, 0xd1, 0x46, 0xa8, 0x50, 0xe0,
  24. 14);
  25. #else
  26. #include <functiondiscoverykeys_devpkey.h>
  27. #endif
  28. static bool get_device_info(obs_enum_audio_device_cb cb, void *data, IMMDeviceCollection *collection, UINT idx)
  29. {
  30. IPropertyStore *store = NULL;
  31. IMMDevice *device = NULL;
  32. PROPVARIANT name_var;
  33. char utf8_name[512];
  34. WCHAR *w_id = NULL;
  35. char utf8_id[512];
  36. bool cont = true;
  37. HRESULT hr;
  38. hr = collection->lpVtbl->Item(collection, idx, &device);
  39. if (FAILED(hr)) {
  40. goto fail;
  41. }
  42. hr = device->lpVtbl->GetId(device, &w_id);
  43. if (FAILED(hr)) {
  44. goto fail;
  45. }
  46. hr = device->lpVtbl->OpenPropertyStore(device, STGM_READ, &store);
  47. if (FAILED(hr)) {
  48. goto fail;
  49. }
  50. PropVariantInit(&name_var);
  51. hr = store->lpVtbl->GetValue(store, &PKEY_Device_FriendlyName, &name_var);
  52. if (FAILED(hr)) {
  53. goto fail;
  54. }
  55. os_wcs_to_utf8(w_id, 0, utf8_id, 512);
  56. os_wcs_to_utf8(name_var.pwszVal, 0, utf8_name, 512);
  57. cont = cb(data, utf8_name, utf8_id);
  58. PropVariantClear(&name_var);
  59. fail:
  60. safe_release(store);
  61. safe_release(device);
  62. if (w_id)
  63. CoTaskMemFree(w_id);
  64. return cont;
  65. }
  66. void obs_enum_audio_monitoring_devices(obs_enum_audio_device_cb cb, void *data)
  67. {
  68. IMMDeviceEnumerator *enumerator = NULL;
  69. IMMDeviceCollection *collection = NULL;
  70. UINT count;
  71. HRESULT hr;
  72. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, &enumerator);
  73. if (FAILED(hr)) {
  74. goto fail;
  75. }
  76. hr = enumerator->lpVtbl->EnumAudioEndpoints(enumerator, eRender, DEVICE_STATE_ACTIVE, &collection);
  77. if (FAILED(hr)) {
  78. goto fail;
  79. }
  80. hr = collection->lpVtbl->GetCount(collection, &count);
  81. if (FAILED(hr)) {
  82. goto fail;
  83. }
  84. for (UINT i = 0; i < count; i++) {
  85. if (!get_device_info(cb, data, collection, i)) {
  86. break;
  87. }
  88. }
  89. fail:
  90. safe_release(enumerator);
  91. safe_release(collection);
  92. }
  93. static void get_default_id(char **p_id)
  94. {
  95. IMMDeviceEnumerator *immde = NULL;
  96. IMMDevice *device = NULL;
  97. WCHAR *w_id = NULL;
  98. HRESULT hr;
  99. if (*p_id)
  100. return;
  101. hr = CoCreateInstance(&CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, &IID_IMMDeviceEnumerator, &immde);
  102. if (FAILED(hr)) {
  103. goto fail;
  104. }
  105. hr = immde->lpVtbl->GetDefaultAudioEndpoint(immde, eRender, eConsole, &device);
  106. if (FAILED(hr)) {
  107. goto fail;
  108. }
  109. hr = device->lpVtbl->GetId(device, &w_id);
  110. if (FAILED(hr)) {
  111. goto fail;
  112. }
  113. os_wcs_to_utf8_ptr(w_id, 0, p_id);
  114. fail:
  115. if (!*p_id)
  116. *p_id = bzalloc(1);
  117. if (immde)
  118. immde->lpVtbl->Release(immde);
  119. if (device)
  120. device->lpVtbl->Release(device);
  121. if (w_id)
  122. CoTaskMemFree(w_id);
  123. }
  124. bool devices_match(const char *id1, const char *id2)
  125. {
  126. char *default_id = NULL;
  127. bool match;
  128. if (!id1 || !id2)
  129. return false;
  130. if (strcmp(id1, "default") == 0) {
  131. get_default_id(&default_id);
  132. id1 = default_id;
  133. }
  134. if (strcmp(id2, "default") == 0) {
  135. get_default_id(&default_id);
  136. id2 = default_id;
  137. }
  138. match = strcmp(id1, id2) == 0;
  139. bfree(default_id);
  140. return match;
  141. }