event.cpp 7.7 KB

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