1
0

wasapi-enum-devices.c 3.2 KB

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