aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--al/event.cpp94
-rw-r--r--alc/alu.cpp31
-rw-r--r--core/async_event.h89
-rw-r--r--core/context.h3
-rw-r--r--core/voice.cpp20
5 files changed, 129 insertions, 108 deletions
diff --git a/al/event.cpp b/al/event.cpp
index 4fa1bf56..eb6af45c 100644
--- a/al/event.cpp
+++ b/al/event.cpp
@@ -32,7 +32,15 @@
#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};
@@ -51,81 +59,87 @@ static int EventThread(ALCcontext *context)
evt_data.buf += sizeof(AsyncEvent);
evt_data.len -= 1;
- AsyncEvent evt{*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) 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(!enabledevts.test(AsyncEvent::SourceStateChange))
- continue;
+ 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)
{
- if(!enabledevts.test(AsyncEvent::BufferCompleted))
- continue;
+ if(!context->mEventCb
+ || !enabledevts.test(al::to_underlying(AsyncEnableBits::BufferCompleted)))
+ return;
- std::string msg{std::to_string(evt.u.bufcomp.count)};
- if(evt.u.bufcomp.count == 1) msg += " buffer completed";
+ 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)
{
- const std::string_view message{evt.u.disconnect.msg};
+ const std::string_view message{evt.msg};
context->debugMessage(DebugSource::System, DebugType::Error, 0,
DebugSeverity::High, static_cast<ALsizei>(message.length()), message.data());
- if(enabledevts.test(AsyncEvent::Disconnected))
+ 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;
}
+} // namespace
+
+
void StartEventThrd(ALCcontext *ctx)
{
try {
@@ -150,7 +164,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>(reinterpret_cast<AsyncEvent*>(evt_data.buf));
ring->writeAdvance(1);
ctx->mEventSem.post();
@@ -174,11 +188,11 @@ START_API_FUNC
[&flags](ALenum type) noexcept -> bool
{
if(type == AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT)
- flags.set(AsyncEvent::BufferCompleted);
+ flags.set(al::to_underlying(AsyncEnableBits::BufferCompleted));
else if(type == AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT)
- flags.set(AsyncEvent::SourceStateChange);
+ flags.set(al::to_underlying(AsyncEnableBits::SourceState));
else if(type == AL_EVENT_TYPE_DISCONNECTED_SOFT)
- flags.set(AsyncEvent::Disconnected);
+ flags.set(al::to_underlying(AsyncEnableBits::Disconnected));
else
return false;
return true;
diff --git a/alc/alu.cpp b/alc/alu.cpp
index 1157aca3..cf250988 100644
--- a/alc/alu.cpp
+++ b/alc/alu.cpp
@@ -491,9 +491,9 @@ bool CalcEffectSlotParams(EffectSlot *slot, EffectSlot **sorted_slots, ContextBa
auto evt_vec = ring->getWriteVector();
if(evt_vec.first.len > 0) LIKELY
{
- AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
- AsyncEvent::ReleaseEffectState)};
- evt->u.mEffectState = oldstate;
+ AsyncEffectReleaseEvent &evt = InitAsyncEvent<AsyncEffectReleaseEvent>(
+ reinterpret_cast<AsyncEvent*>(evt_vec.first.buf));
+ evt.mEffectState = oldstate;
ring->writeAdvance(1);
}
else
@@ -1701,22 +1701,22 @@ void SendSourceStateEvent(ContextBase *context, uint id, VChangeState state)
auto evt_vec = ring->getWriteVector();
if(evt_vec.first.len < 1) return;
- AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
- AsyncEvent::SourceStateChange)};
- evt->u.srcstate.id = id;
+ AsyncSourceStateEvent &evt = InitAsyncEvent<AsyncSourceStateEvent>(
+ reinterpret_cast<AsyncEvent*>(evt_vec.first.buf));
+ evt.mId = id;
switch(state)
{
case VChangeState::Reset:
- evt->u.srcstate.state = AsyncEvent::SrcState::Reset;
+ evt.mState = AsyncSrcState::Reset;
break;
case VChangeState::Stop:
- evt->u.srcstate.state = AsyncEvent::SrcState::Stop;
+ evt.mState = AsyncSrcState::Stop;
break;
case VChangeState::Play:
- evt->u.srcstate.state = AsyncEvent::SrcState::Play;
+ evt.mState = AsyncSrcState::Play;
break;
case VChangeState::Pause:
- evt->u.srcstate.state = AsyncEvent::SrcState::Pause;
+ evt.mState = AsyncSrcState::Pause;
break;
/* Shouldn't happen. */
case VChangeState::Restart:
@@ -1813,7 +1813,7 @@ void ProcessVoiceChanges(ContextBase *ctx)
}
oldvoice->mPendingChange.store(false, std::memory_order_release);
}
- if(sendevt && enabledevt.test(AsyncEvent::SourceStateChange))
+ if(sendevt && enabledevt.test(al::to_underlying(AsyncEnableBits::SourceState)))
SendSourceStateEvent(ctx, cur->mSourceID, cur->mState);
next = cur->mNext.load(std::memory_order_acquire);
@@ -2166,15 +2166,16 @@ void DeviceBase::handleDisconnect(const char *msg, ...)
IncrementRef(MixCount);
if(Connected.exchange(false, std::memory_order_acq_rel))
{
- AsyncEvent evt{AsyncEvent::Disconnected};
+ AsyncEvent evt{std::in_place_type<AsyncDisconnectEvent>};
+ auto &disconnect = std::get<AsyncDisconnectEvent>(evt);
va_list args;
va_start(args, msg);
- int msglen{vsnprintf(evt.u.disconnect.msg, sizeof(evt.u.disconnect.msg), msg, args)};
+ int msglen{vsnprintf(disconnect.msg, sizeof(disconnect.msg), msg, args)};
va_end(args);
- if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(evt.u.disconnect.msg))
- evt.u.disconnect.msg[sizeof(evt.u.disconnect.msg)-1] = 0;
+ if(msglen < 0 || static_cast<size_t>(msglen) >= sizeof(disconnect.msg))
+ disconnect.msg[sizeof(disconnect.msg)-1] = 0;
for(ContextBase *ctx : *mContexts.load())
{
diff --git a/core/async_event.h b/core/async_event.h
index 5a2f5f91..9e2d1193 100644
--- a/core/async_event.h
+++ b/core/async_event.h
@@ -1,6 +1,9 @@
#ifndef CORE_EVENT_H
#define CORE_EVENT_H
+#include <stdint.h>
+#include <variant>
+
#include "almalloc.h"
struct EffectState;
@@ -8,48 +11,50 @@ struct EffectState;
using uint = unsigned int;
-struct AsyncEvent {
- enum : uint {
- /* User event types. */
- SourceStateChange,
- BufferCompleted,
- Disconnected,
- UserEventCount,
-
- /* Internal events, always processed. */
- ReleaseEffectState = 128,
-
- /* End event thread processing. */
- KillThread,
- };
-
- enum class SrcState {
- Reset,
- Stop,
- Play,
- Pause
- };
-
- const uint EnumType;
- union {
- char dummy;
- struct {
- uint id;
- SrcState state;
- } srcstate;
- struct {
- uint id;
- uint count;
- } bufcomp;
- struct {
- char msg[244];
- } disconnect;
- EffectState *mEffectState;
- } u{};
-
- constexpr AsyncEvent(uint type) noexcept : EnumType{type} { }
-
- DISABLE_ALLOC()
+enum class AsyncEnableBits : uint8_t {
+ SourceState,
+ BufferCompleted,
+ Disconnected,
+
+ Count
+};
+
+
+enum class AsyncSrcState : uint8_t {
+ Reset,
+ Stop,
+ Play,
+ Pause
+};
+
+using AsyncKillThread = std::monostate;
+
+struct AsyncSourceStateEvent {
+ uint mId;
+ AsyncSrcState mState;
};
+struct AsyncBufferCompleteEvent {
+ uint mId;
+ uint mCount;
+};
+
+struct AsyncDisconnectEvent {
+ char msg[244];
+};
+
+struct AsyncEffectReleaseEvent {
+ EffectState *mEffectState;
+};
+
+using AsyncEvent = std::variant<AsyncKillThread,
+ AsyncSourceStateEvent,
+ AsyncBufferCompleteEvent,
+ AsyncEffectReleaseEvent,
+ AsyncDisconnectEvent>;
+
+template<typename T, typename ...Args>
+auto &InitAsyncEvent(AsyncEvent *evt, Args&& ...args)
+{ return std::get<T>(*al::construct_at(evt, std::in_place_type<T>, std::forward<Args>(args)...)); }
+
#endif
diff --git a/core/context.h b/core/context.h
index 9723eac3..4febd38d 100644
--- a/core/context.h
+++ b/core/context.h
@@ -13,6 +13,7 @@
#include "async_event.h"
#include "atomic.h"
#include "bufferline.h"
+#include "opthelpers.h"
#include "threads.h"
#include "vecmat.h"
#include "vector.h"
@@ -137,7 +138,7 @@ struct ContextBase {
std::thread mEventThread;
al::semaphore mEventSem;
std::unique_ptr<RingBuffer> mAsyncEvents;
- using AsyncEventBitset = std::bitset<AsyncEvent::UserEventCount>;
+ using AsyncEventBitset = std::bitset<al::to_underlying(AsyncEnableBits::Count)>;
std::atomic<AsyncEventBitset> mEnabledEvts{0u};
/* Asynchronous voice change actions are processed as a linked list of
diff --git a/core/voice.cpp b/core/voice.cpp
index 478ea81f..3e78b176 100644
--- a/core/voice.cpp
+++ b/core/voice.cpp
@@ -226,10 +226,10 @@ void SendSourceStoppedEvent(ContextBase *context, uint id)
auto evt_vec = ring->getWriteVector();
if(evt_vec.first.len < 1) return;
- AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
- AsyncEvent::SourceStateChange)};
- evt->u.srcstate.id = id;
- evt->u.srcstate.state = AsyncEvent::SrcState::Stop;
+ AsyncSourceStateEvent &evt = InitAsyncEvent<AsyncSourceStateEvent>(
+ reinterpret_cast<AsyncEvent*>(evt_vec.first.buf));
+ evt.mId = id;
+ evt.mState = AsyncSrcState::Stop;
ring->writeAdvance(1);
}
@@ -1145,16 +1145,16 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
/* Send any events now, after the position/buffer info was updated. */
const auto enabledevt = Context->mEnabledEvts.load(std::memory_order_acquire);
- if(buffers_done > 0 && enabledevt.test(AsyncEvent::BufferCompleted))
+ if(buffers_done > 0 && enabledevt.test(al::to_underlying(AsyncEnableBits::BufferCompleted)))
{
RingBuffer *ring{Context->mAsyncEvents.get()};
auto evt_vec = ring->getWriteVector();
if(evt_vec.first.len > 0)
{
- AsyncEvent *evt{al::construct_at(reinterpret_cast<AsyncEvent*>(evt_vec.first.buf),
- AsyncEvent::BufferCompleted)};
- evt->u.bufcomp.id = SourceID;
- evt->u.bufcomp.count = buffers_done;
+ AsyncBufferCompleteEvent &evt = InitAsyncEvent<AsyncBufferCompleteEvent>(
+ reinterpret_cast<AsyncEvent*>(evt_vec.first.buf));
+ evt.mId = SourceID;
+ evt.mCount = buffers_done;
ring->writeAdvance(1);
}
}
@@ -1165,7 +1165,7 @@ void Voice::mix(const State vstate, ContextBase *Context, const nanoseconds devi
* ensures any residual noise fades to 0 amplitude.
*/
mPlayState.store(Stopping, std::memory_order_release);
- if(enabledevt.test(AsyncEvent::SourceStateChange))
+ if(enabledevt.test(al::to_underlying(AsyncEnableBits::SourceState)))
SendSourceStoppedEvent(Context, SourceID);
}
}