event.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. #include "config.h"
  2. #include "event.h"
  3. #include <atomic>
  4. #include <bitset>
  5. #include <exception>
  6. #include <memory>
  7. #include <mutex>
  8. #include <new>
  9. #include <optional>
  10. #include <string>
  11. #include <thread>
  12. #include <tuple>
  13. #include <variant>
  14. #include "AL/al.h"
  15. #include "AL/alc.h"
  16. #include "AL/alext.h"
  17. #include "alc/context.h"
  18. #include "alnumeric.h"
  19. #include "alsem.h"
  20. #include "alspan.h"
  21. #include "alstring.h"
  22. #include "core/async_event.h"
  23. #include "core/context.h"
  24. #include "core/effects/base.h"
  25. #include "core/except.h"
  26. #include "core/logging.h"
  27. #include "debug.h"
  28. #include "direct_defs.h"
  29. #include "intrusive_ptr.h"
  30. #include "opthelpers.h"
  31. #include "ringbuffer.h"
  32. namespace {
  33. template<typename... Ts>
  34. struct overloaded : Ts... { using Ts::operator()...; };
  35. template<typename... Ts>
  36. overloaded(Ts...) -> overloaded<Ts...>;
  37. int EventThread(ALCcontext *context)
  38. {
  39. RingBuffer *ring{context->mAsyncEvents.get()};
  40. bool quitnow{false};
  41. while(!quitnow)
  42. {
  43. auto evt_data = ring->getReadVector()[0];
  44. if(evt_data.len == 0)
  45. {
  46. context->mEventSem.wait();
  47. continue;
  48. }
  49. auto eventlock = std::lock_guard{context->mEventCbLock};
  50. const auto enabledevts = context->mEnabledEvts.load(std::memory_order_acquire);
  51. auto evt_span = al::span{std::launder(reinterpret_cast<AsyncEvent*>(evt_data.buf)),
  52. evt_data.len};
  53. for(auto &event : evt_span)
  54. {
  55. quitnow = std::holds_alternative<AsyncKillThread>(event);
  56. if(quitnow) UNLIKELY break;
  57. auto proc_killthread = [](AsyncKillThread&) { };
  58. auto proc_release = [](AsyncEffectReleaseEvent &evt)
  59. {
  60. al::intrusive_ptr<EffectState>{evt.mEffectState};
  61. };
  62. auto proc_srcstate = [context,enabledevts](AsyncSourceStateEvent &evt)
  63. {
  64. if(!context->mEventCb
  65. || !enabledevts.test(al::to_underlying(AsyncEnableBits::SourceState)))
  66. return;
  67. ALuint state{};
  68. std::string msg{"Source ID " + std::to_string(evt.mId)};
  69. msg += " state has changed to ";
  70. switch(evt.mState)
  71. {
  72. case AsyncSrcState::Reset:
  73. msg += "AL_INITIAL";
  74. state = AL_INITIAL;
  75. break;
  76. case AsyncSrcState::Stop:
  77. msg += "AL_STOPPED";
  78. state = AL_STOPPED;
  79. break;
  80. case AsyncSrcState::Play:
  81. msg += "AL_PLAYING";
  82. state = AL_PLAYING;
  83. break;
  84. case AsyncSrcState::Pause:
  85. msg += "AL_PAUSED";
  86. state = AL_PAUSED;
  87. break;
  88. }
  89. context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.mId, state,
  90. al::sizei(msg), msg.c_str(), context->mEventParam);
  91. };
  92. auto proc_buffercomp = [context,enabledevts](AsyncBufferCompleteEvent &evt)
  93. {
  94. if(!context->mEventCb
  95. || !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted)))
  96. return;
  97. std::string msg{std::to_string(evt.mCount)};
  98. if(evt.mCount == 1) msg += " buffer completed";
  99. else msg += " buffers completed";
  100. context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.mId, evt.mCount,
  101. al::sizei(msg), msg.c_str(), context->mEventParam);
  102. };
  103. auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt)
  104. {
  105. if(!context->mEventCb
  106. || !enabledevts.test(al::to_underlying(AsyncEnableBits::Disconnected)))
  107. return;
  108. context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, al::sizei(evt.msg),
  109. evt.msg.c_str(), context->mEventParam);
  110. };
  111. std::visit(overloaded{proc_srcstate, proc_buffercomp, proc_release, proc_disconnect,
  112. proc_killthread}, event);
  113. }
  114. std::destroy(evt_span.begin(), evt_span.end());
  115. ring->readAdvance(evt_span.size());
  116. }
  117. return 0;
  118. }
  119. constexpr std::optional<AsyncEnableBits> GetEventType(ALenum etype) noexcept
  120. {
  121. switch(etype)
  122. {
  123. case AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT: return AsyncEnableBits::BufferCompleted;
  124. case AL_EVENT_TYPE_DISCONNECTED_SOFT: return AsyncEnableBits::Disconnected;
  125. case AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT: return AsyncEnableBits::SourceState;
  126. }
  127. return std::nullopt;
  128. }
  129. } // namespace
  130. void StartEventThrd(ALCcontext *ctx)
  131. {
  132. try {
  133. ctx->mEventThread = std::thread{EventThread, ctx};
  134. }
  135. catch(std::exception& e) {
  136. ERR("Failed to start event thread: {}", e.what());
  137. }
  138. catch(...) {
  139. ERR("Failed to start event thread! Expect problems.");
  140. }
  141. }
  142. void StopEventThrd(ALCcontext *ctx)
  143. {
  144. RingBuffer *ring{ctx->mAsyncEvents.get()};
  145. auto evt_data = ring->getWriteVector()[0];
  146. if(evt_data.len == 0)
  147. {
  148. do {
  149. std::this_thread::yield();
  150. evt_data = ring->getWriteVector()[0];
  151. } while(evt_data.len == 0);
  152. }
  153. std::ignore = InitAsyncEvent<AsyncKillThread>(evt_data.buf);
  154. ring->writeAdvance(1);
  155. ctx->mEventSem.post();
  156. if(ctx->mEventThread.joinable())
  157. ctx->mEventThread.join();
  158. }
  159. AL_API DECL_FUNCEXT3(void, alEventControl,SOFT, ALsizei,count, const ALenum*,types, ALboolean,enable)
  160. FORCE_ALIGN void AL_APIENTRY alEventControlDirectSOFT(ALCcontext *context, ALsizei count,
  161. const ALenum *types, ALboolean enable) noexcept
  162. try {
  163. if(count < 0)
  164. context->throw_error(AL_INVALID_VALUE, "Controlling {} events", count);
  165. if(count <= 0) UNLIKELY return;
  166. if(!types)
  167. context->throw_error(AL_INVALID_VALUE, "NULL pointer");
  168. ContextBase::AsyncEventBitset flags{};
  169. for(ALenum evttype : al::span{types, static_cast<uint>(count)})
  170. {
  171. auto etype = GetEventType(evttype);
  172. if(!etype)
  173. context->throw_error(AL_INVALID_ENUM, "Invalid event type {:#04x}",
  174. as_unsigned(evttype));
  175. flags.set(al::to_underlying(*etype));
  176. }
  177. if(enable)
  178. {
  179. auto enabledevts = context->mEnabledEvts.load(std::memory_order_relaxed);
  180. while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags,
  181. std::memory_order_acq_rel, std::memory_order_acquire) == 0)
  182. {
  183. /* enabledevts is (re-)filled with the current value on failure, so
  184. * just try again.
  185. */
  186. }
  187. }
  188. else
  189. {
  190. auto enabledevts = context->mEnabledEvts.load(std::memory_order_relaxed);
  191. while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags,
  192. std::memory_order_acq_rel, std::memory_order_acquire) == 0)
  193. {
  194. }
  195. /* Wait to ensure the event handler sees the changed flags before
  196. * returning.
  197. */
  198. std::lock_guard<std::mutex> eventlock{context->mEventCbLock};
  199. }
  200. }
  201. catch(al::base_exception&) {
  202. }
  203. catch(std::exception &e) {
  204. ERR("Caught exception: {}", e.what());
  205. }
  206. AL_API DECL_FUNCEXT2(void, alEventCallback,SOFT, ALEVENTPROCSOFT,callback, void*,userParam)
  207. FORCE_ALIGN void AL_APIENTRY alEventCallbackDirectSOFT(ALCcontext *context,
  208. ALEVENTPROCSOFT callback, void *userParam) noexcept
  209. try {
  210. std::lock_guard<std::mutex> eventlock{context->mEventCbLock};
  211. context->mEventCb = callback;
  212. context->mEventParam = userParam;
  213. }
  214. catch(al::base_exception&) {
  215. }
  216. catch(std::exception &e) {
  217. ERR("Caught exception: {}", e.what());
  218. }