wasapi-notify.cpp 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. #include "wasapi-notify.hpp"
  2. #include <windows.h>
  3. #include <assert.h>
  4. #include <util/threading.h>
  5. class NotificationClient : public IMMNotificationClient {
  6. volatile long refs = 1;
  7. WASAPINotifyDefaultDeviceChangedCallback cb;
  8. public:
  9. NotificationClient(WASAPINotifyDefaultDeviceChangedCallback cb) : cb(cb)
  10. {
  11. assert(cb);
  12. }
  13. STDMETHODIMP_(ULONG) AddRef()
  14. {
  15. return (ULONG)os_atomic_inc_long(&refs);
  16. }
  17. STDMETHODIMP_(ULONG) STDMETHODCALLTYPE Release()
  18. {
  19. long val = os_atomic_dec_long(&refs);
  20. if (val == 0)
  21. delete this;
  22. return (ULONG)val;
  23. }
  24. STDMETHODIMP QueryInterface(REFIID riid, void **ptr)
  25. {
  26. if (riid == IID_IUnknown) {
  27. *ptr = (IUnknown *)this;
  28. } else if (riid == __uuidof(IMMNotificationClient)) {
  29. *ptr = (IMMNotificationClient *)this;
  30. } else {
  31. *ptr = nullptr;
  32. return E_NOINTERFACE;
  33. }
  34. InterlockedIncrement(&refs);
  35. return S_OK;
  36. }
  37. STDMETHODIMP OnDeviceAdded(LPCWSTR) { return S_OK; }
  38. STDMETHODIMP OnDeviceRemoved(LPCWSTR) { return S_OK; }
  39. STDMETHODIMP OnDeviceStateChanged(LPCWSTR, DWORD) { return S_OK; }
  40. STDMETHODIMP OnPropertyValueChanged(LPCWSTR, const PROPERTYKEY)
  41. {
  42. return S_OK;
  43. }
  44. STDMETHODIMP OnDefaultDeviceChanged(EDataFlow flow, ERole role,
  45. LPCWSTR id)
  46. {
  47. if (cb && id)
  48. cb(flow, role, id);
  49. return S_OK;
  50. }
  51. };
  52. WASAPINotify::WASAPINotify()
  53. {
  54. HRESULT res = CoCreateInstance(__uuidof(MMDeviceEnumerator), nullptr,
  55. CLSCTX_ALL,
  56. __uuidof(IMMDeviceEnumerator),
  57. (LPVOID *)enumerator.Assign());
  58. if (SUCCEEDED(res)) {
  59. notificationClient = new NotificationClient(
  60. std::bind(&WASAPINotify::OnDefaultDeviceChanged, this,
  61. std::placeholders::_1, std::placeholders::_2,
  62. std::placeholders::_3));
  63. enumerator->RegisterEndpointNotificationCallback(
  64. notificationClient);
  65. } else {
  66. enumerator.Clear();
  67. }
  68. }
  69. WASAPINotify::~WASAPINotify()
  70. {
  71. if (enumerator) {
  72. enumerator->UnregisterEndpointNotificationCallback(
  73. notificationClient);
  74. enumerator.Clear();
  75. }
  76. notificationClient.Clear();
  77. }
  78. void WASAPINotify::AddDefaultDeviceChangedCallback(
  79. void *handle, WASAPINotifyDefaultDeviceChangedCallback cb)
  80. {
  81. if (!handle)
  82. return;
  83. std::lock_guard<std::mutex> l(mutex);
  84. defaultDeviceChangedCallbacks[handle] = cb;
  85. }
  86. void WASAPINotify::RemoveDefaultDeviceChangedCallback(void *handle)
  87. {
  88. if (!handle)
  89. return;
  90. std::lock_guard<std::mutex> l(mutex);
  91. defaultDeviceChangedCallbacks.erase(handle);
  92. }
  93. void WASAPINotify::OnDefaultDeviceChanged(EDataFlow flow, ERole role,
  94. LPCWSTR id)
  95. {
  96. std::lock_guard<std::mutex> l(mutex);
  97. for (const auto &cb : defaultDeviceChangedCallbacks)
  98. cb.second(flow, role, id);
  99. }