🛠️🐜 Antkeeper superbuild with dependencies included https://antkeeper.com
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.0 KiB

  1. #include "config.h"
  2. #include "event.h"
  3. #include <algorithm>
  4. #include <atomic>
  5. #include <cstring>
  6. #include <exception>
  7. #include <memory>
  8. #include <mutex>
  9. #include <new>
  10. #include <string>
  11. #include <thread>
  12. #include <utility>
  13. #include "AL/al.h"
  14. #include "AL/alc.h"
  15. #include "albyte.h"
  16. #include "alc/context.h"
  17. #include "alc/effects/base.h"
  18. #include "alc/inprogext.h"
  19. #include "almalloc.h"
  20. #include "core/async_event.h"
  21. #include "core/except.h"
  22. #include "core/logging.h"
  23. #include "core/voice_change.h"
  24. #include "opthelpers.h"
  25. #include "ringbuffer.h"
  26. #include "threads.h"
  27. static int EventThread(ALCcontext *context)
  28. {
  29. RingBuffer *ring{context->mAsyncEvents.get()};
  30. bool quitnow{false};
  31. while(likely(!quitnow))
  32. {
  33. auto evt_data = ring->getReadVector().first;
  34. if(evt_data.len == 0)
  35. {
  36. context->mEventSem.wait();
  37. continue;
  38. }
  39. std::lock_guard<std::mutex> _{context->mEventCbLock};
  40. do {
  41. auto *evt_ptr = reinterpret_cast<AsyncEvent*>(evt_data.buf);
  42. evt_data.buf += sizeof(AsyncEvent);
  43. evt_data.len -= 1;
  44. AsyncEvent evt{*evt_ptr};
  45. al::destroy_at(evt_ptr);
  46. ring->readAdvance(1);
  47. quitnow = evt.EnumType == AsyncEvent::KillThread;
  48. if(unlikely(quitnow)) break;
  49. if(evt.EnumType == AsyncEvent::ReleaseEffectState)
  50. {
  51. evt.u.mEffectState->release();
  52. continue;
  53. }
  54. uint enabledevts{context->mEnabledEvts.load(std::memory_order_acquire)};
  55. if(!context->mEventCb) continue;
  56. if(evt.EnumType == AsyncEvent::SourceStateChange)
  57. {
  58. if(!(enabledevts&AsyncEvent::SourceStateChange))
  59. continue;
  60. ALuint state{};
  61. std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)};
  62. msg += " state has changed to ";
  63. switch(evt.u.srcstate.state)
  64. {
  65. case AsyncEvent::SrcState::Reset:
  66. msg += "AL_INITIAL";
  67. state = AL_INITIAL;
  68. break;
  69. case AsyncEvent::SrcState::Stop:
  70. msg += "AL_STOPPED";
  71. state = AL_STOPPED;
  72. break;
  73. case AsyncEvent::SrcState::Play:
  74. msg += "AL_PLAYING";
  75. state = AL_PLAYING;
  76. break;
  77. case AsyncEvent::SrcState::Pause:
  78. msg += "AL_PAUSED";
  79. state = AL_PAUSED;
  80. break;
  81. }
  82. context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id,
  83. state, static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam);
  84. }
  85. else if(evt.EnumType == AsyncEvent::BufferCompleted)
  86. {
  87. if(!(enabledevts&AsyncEvent::BufferCompleted))
  88. continue;
  89. std::string msg{std::to_string(evt.u.bufcomp.count)};
  90. if(evt.u.bufcomp.count == 1) msg += " buffer completed";
  91. else msg += " buffers completed";
  92. context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id,
  93. evt.u.bufcomp.count, static_cast<ALsizei>(msg.length()), msg.c_str(),
  94. context->mEventParam);
  95. }
  96. else if(evt.EnumType == AsyncEvent::Disconnected)
  97. {
  98. if(!(enabledevts&AsyncEvent::Disconnected))
  99. continue;
  100. context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0,
  101. static_cast<ALsizei>(strlen(evt.u.disconnect.msg)), evt.u.disconnect.msg,
  102. context->mEventParam);
  103. }
  104. } while(evt_data.len != 0);
  105. }
  106. return 0;
  107. }
  108. void StartEventThrd(ALCcontext *ctx)
  109. {
  110. try {
  111. ctx->mEventThread = std::thread{EventThread, ctx};
  112. }
  113. catch(std::exception& e) {
  114. ERR("Failed to start event thread: %s\n", e.what());
  115. }
  116. catch(...) {
  117. ERR("Failed to start event thread! Expect problems.\n");
  118. }
  119. }
  120. void StopEventThrd(ALCcontext *ctx)
  121. {
  122. RingBuffer *ring{ctx->mAsyncEvents.get()};
  123. auto evt_data = ring->getWriteVector().first;
  124. if(evt_data.len == 0)
  125. {
  126. do {
  127. std::this_thread::yield();
  128. evt_data = ring->getWriteVector().first;
  129. } while(evt_data.len == 0);
  130. }
  131. al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread);
  132. ring->writeAdvance(1);
  133. ctx->mEventSem.post();
  134. if(ctx->mEventThread.joinable())
  135. ctx->mEventThread.join();
  136. }
  137. AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable)
  138. START_API_FUNC
  139. {
  140. ContextRef context{GetContextRef()};
  141. if(unlikely(!context)) return;
  142. if(count < 0) context->setError(AL_INVALID_VALUE, "Controlling %d events", count);
  143. if(count <= 0) return;
  144. if(!types) SETERR_RETURN(context, AL_INVALID_VALUE,, "NULL pointer");
  145. uint flags{0};
  146. const ALenum *types_end = types+count;
  147. auto bad_type = std::find_if_not(types, types_end,
  148. [&flags](ALenum type) noexcept -> bool
  149. {
  150. if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
  151. flags |= AsyncEvent::BufferCompleted;
  152. else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
  153. flags |= AsyncEvent::SourceStateChange;
  154. else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT)
  155. flags |= AsyncEvent::Disconnected;
  156. else
  157. return false;
  158. return true;
  159. }
  160. );
  161. if(bad_type != types_end)
  162. SETERR_RETURN(context, AL_INVALID_ENUM,, "Invalid event type 0x%04x", *bad_type);
  163. if(enable)
  164. {
  165. uint enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)};
  166. while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts|flags,
  167. std::memory_order_acq_rel, std::memory_order_acquire) == 0)
  168. {
  169. /* enabledevts is (re-)filled with the current value on failure, so
  170. * just try again.
  171. */
  172. }
  173. }
  174. else
  175. {
  176. uint enabledevts{context->mEnabledEvts.load(std::memory_order_relaxed)};
  177. while(context->mEnabledEvts.compare_exchange_weak(enabledevts, enabledevts&~flags,
  178. std::memory_order_acq_rel, std::memory_order_acquire) == 0)
  179. {
  180. }
  181. /* Wait to ensure the event handler sees the changed flags before
  182. * returning.
  183. */
  184. std::lock_guard<std::mutex> _{context->mEventCbLock};
  185. }
  186. }
  187. END_API_FUNC
  188. AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam)
  189. START_API_FUNC
  190. {
  191. ContextRef context{GetContextRef()};
  192. if(unlikely(!context)) return;
  193. std::lock_guard<std::mutex> _{context->mPropLock};
  194. std::lock_guard<std::mutex> __{context->mEventCbLock};
  195. context->mEventCb = callback;
  196. context->mEventParam = userParam;
  197. }
  198. END_API_FUNC