diff options
author | Sven Gothel <[email protected]> | 2023-11-28 12:51:46 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2023-11-28 12:51:46 +0100 |
commit | 1aaf4f070011490bcece50394b9b32dfa593fd9e (patch) | |
tree | 17d68284e401a35eea3d3a574d986d446a60763a /al/event.cpp | |
parent | 6e7cee4fa9a8af03f28ca26cd89f8357390dfc90 (diff) | |
parent | 571b546f35eead77ce109f8d4dd6c3de3199d573 (diff) |
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'al/event.cpp')
-rw-r--r-- | al/event.cpp | 160 |
1 files changed, 90 insertions, 70 deletions
diff --git a/al/event.cpp b/al/event.cpp index 1bc39d1e..8b76ceff 100644 --- a/al/event.cpp +++ b/al/event.cpp @@ -10,14 +10,15 @@ #include <memory> #include <mutex> #include <new> +#include <optional> #include <string> +#include <string_view> #include <thread> #include <utility> #include "AL/al.h" #include "AL/alc.h" -#include "albyte.h" #include "alc/context.h" #include "alc/effects/base.h" #include "alc/inprogext.h" @@ -26,12 +27,21 @@ #include "core/except.h" #include "core/logging.h" #include "core/voice_change.h" +#include "debug.h" +#include "direct_defs.h" #include "opthelpers.h" #include "ringbuffer.h" -#include "threads.h" -static int EventThread(ALCcontext *context) +namespace { + +template<typename... Ts> +struct overloaded : Ts... { using Ts::operator()...; }; + +template<typename... Ts> +overloaded(Ts...) -> overloaded<Ts...>; + +int EventThread(ALCcontext *context) { RingBuffer *ring{context->mAsyncEvents.get()}; bool quitnow{false}; @@ -46,74 +56,101 @@ static int EventThread(ALCcontext *context) std::lock_guard<std::mutex> _{context->mEventCbLock}; do { - auto *evt_ptr = reinterpret_cast<AsyncEvent*>(evt_data.buf); + auto *evt_ptr = std::launder(reinterpret_cast<AsyncEvent*>(evt_data.buf)); evt_data.buf += sizeof(AsyncEvent); evt_data.len -= 1; - AsyncEvent evt{*evt_ptr}; - al::destroy_at(evt_ptr); + AsyncEvent event{std::move(*evt_ptr)}; + std::destroy_at(evt_ptr); ring->readAdvance(1); - quitnow = evt.EnumType == AsyncEvent::KillThread; + quitnow = std::holds_alternative<AsyncKillThread>(event); if(quitnow) UNLIKELY break; - if(evt.EnumType == AsyncEvent::ReleaseEffectState) - { - al::intrusive_ptr<EffectState>{evt.u.mEffectState}; - continue; - } - auto enabledevts = context->mEnabledEvts.load(std::memory_order_acquire); - if(!context->mEventCb || !enabledevts.test(evt.EnumType)) - continue; - - if(evt.EnumType == AsyncEvent::SourceStateChange) + auto proc_killthread = [](AsyncKillThread&) { }; + auto proc_release = [](AsyncEffectReleaseEvent &evt) + { + al::intrusive_ptr<EffectState>{evt.mEffectState}; + }; + auto proc_srcstate = [context,enabledevts](AsyncSourceStateEvent &evt) { + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::SourceState))) + return; + ALuint state{}; - std::string msg{"Source ID " + std::to_string(evt.u.srcstate.id)}; + std::string msg{"Source ID " + std::to_string(evt.mId)}; msg += " state has changed to "; - switch(evt.u.srcstate.state) + switch(evt.mState) { - case AsyncEvent::SrcState::Reset: + case AsyncSrcState::Reset: msg += "AL_INITIAL"; state = AL_INITIAL; break; - case AsyncEvent::SrcState::Stop: + case AsyncSrcState::Stop: msg += "AL_STOPPED"; state = AL_STOPPED; break; - case AsyncEvent::SrcState::Play: + case AsyncSrcState::Play: msg += "AL_PLAYING"; state = AL_PLAYING; break; - case AsyncEvent::SrcState::Pause: + case AsyncSrcState::Pause: msg += "AL_PAUSED"; state = AL_PAUSED; break; } - context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.u.srcstate.id, - state, static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::BufferCompleted) + context->mEventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT, evt.mId, state, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_buffercomp = [context,enabledevts](AsyncBufferCompleteEvent &evt) { - std::string msg{std::to_string(evt.u.bufcomp.count)}; - if(evt.u.bufcomp.count == 1) msg += " buffer completed"; + if(!context->mEventCb + || !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted))) + return; + + std::string msg{std::to_string(evt.mCount)}; + if(evt.mCount == 1) msg += " buffer completed"; else msg += " buffers completed"; - context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.u.bufcomp.id, - evt.u.bufcomp.count, static_cast<ALsizei>(msg.length()), msg.c_str(), - context->mEventParam); - } - else if(evt.EnumType == AsyncEvent::Disconnected) + context->mEventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT, evt.mId, evt.mCount, + static_cast<ALsizei>(msg.length()), msg.c_str(), context->mEventParam); + }; + auto proc_disconnect = [context,enabledevts](AsyncDisconnectEvent &evt) { - context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, - static_cast<ALsizei>(strlen(evt.u.disconnect.msg)), evt.u.disconnect.msg, - context->mEventParam); - } + const std::string_view message{evt.msg}; + + context->debugMessage(DebugSource::System, DebugType::Error, 0, + DebugSeverity::High, message); + + if(context->mEventCb + && enabledevts.test(al::to_underlying(AsyncEnableBits::Disconnected))) + context->mEventCb(AL_EVENT_TYPE_DISCONNECTED_SOFT, 0, 0, + static_cast<ALsizei>(message.length()), message.data(), + context->mEventParam); + }; + + std::visit(overloaded{proc_srcstate, proc_buffercomp, proc_release, proc_disconnect, + proc_killthread}, event); } while(evt_data.len != 0); } return 0; } +constexpr std::optional<AsyncEnableBits> GetEventType(ALenum etype) noexcept +{ + switch(etype) + { + case AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT: return AsyncEnableBits::BufferCompleted; + case AL_EVENT_TYPE_DISCONNECTED_SOFT: return AsyncEnableBits::Disconnected; + case AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT: return AsyncEnableBits::SourceState; + } + return std::nullopt; +} + +} // namespace + + void StartEventThrd(ALCcontext *ctx) { try { @@ -138,7 +175,7 @@ void StopEventThrd(ALCcontext *ctx) evt_data = ring->getWriteVector().first; } while(evt_data.len == 0); } - al::construct_at(reinterpret_cast<AsyncEvent*>(evt_data.buf), AsyncEvent::KillThread); + std::ignore = InitAsyncEvent<AsyncKillThread>(evt_data.buf); ring->writeAdvance(1); ctx->mEventSem.post(); @@ -146,34 +183,22 @@ void StopEventThrd(ALCcontext *ctx) ctx->mEventThread.join(); } -AL_API void AL_APIENTRY alEventControlSOFT(ALsizei count, const ALenum *types, ALboolean enable) -START_API_FUNC +AL_API DECL_FUNCEXT3(void, alEventControl,SOFT, ALsizei, const ALenum*, ALboolean) +FORCE_ALIGN void AL_APIENTRY alEventControlDirectSOFT(ALCcontext *context, ALsizei count, + const ALenum *types, ALboolean enable) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - if(count < 0) context->setError(AL_INVALID_VALUE, "Controlling %d events", count); if(count <= 0) return; if(!types) return context->setError(AL_INVALID_VALUE, "NULL pointer"); ContextBase::AsyncEventBitset flags{}; - const ALenum *types_end = types+count; - auto bad_type = std::find_if_not(types, types_end, - [&flags](ALenum type) noexcept -> bool - { - if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT) - flags.set(AsyncEvent::BufferCompleted); - else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT) - flags.set(AsyncEvent::SourceStateChange); - else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT) - flags.set(AsyncEvent::Disconnected); - else - return false; - return true; - } - ); - if(bad_type != types_end) - return context->setError(AL_INVALID_ENUM, "Invalid event type 0x%04x", *bad_type); + for(ALenum evttype : al::span{types, static_cast<uint>(count)}) + { + auto etype = GetEventType(evttype); + if(!etype) + return context->setError(AL_INVALID_ENUM, "Invalid event type 0x%04x", evttype); + flags.set(al::to_underlying(*etype)); + } if(enable) { @@ -199,17 +224,12 @@ START_API_FUNC std::lock_guard<std::mutex> _{context->mEventCbLock}; } } -END_API_FUNC -AL_API void AL_APIENTRY alEventCallbackSOFT(ALEVENTPROCSOFT callback, void *userParam) -START_API_FUNC +AL_API DECL_FUNCEXT2(void, alEventCallback,SOFT, ALEVENTPROCSOFT, void*) +FORCE_ALIGN void AL_APIENTRY alEventCallbackDirectSOFT(ALCcontext *context, + ALEVENTPROCSOFT callback, void *userParam) noexcept { - ContextRef context{GetContextRef()}; - if(!context) UNLIKELY return; - - std::lock_guard<std::mutex> _{context->mPropLock}; - std::lock_guard<std::mutex> __{context->mEventCbLock}; + std::lock_guard<std::mutex> _{context->mEventCbLock}; context->mEventCb = callback; context->mEventParam = userParam; } -END_API_FUNC |