11 #include "alcontext.h"
13 #include "alAuxEffectSlot.h"
14 #include "ringbuffer.h"
18 static int EventThread(ALCcontext
*context
)
21 while(LIKELY(!quitnow
))
24 if(ll_ringbuffer_read(context
->AsyncEvents
, &evt
, 1) == 0)
26 alsem_wait(&context
->EventSem
);
30 std::lock_guard
<std::mutex
> _
{context
->EventCbLock
};
32 quitnow
= evt
.EnumType
== EventType_KillThread
;
33 if(UNLIKELY(quitnow
)) break;
35 if(evt
.EnumType
== EventType_ReleaseEffectState
)
37 evt
.u
.mEffectState
->DecRef();
41 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_acquire
)};
42 if(context
->EventCb
&& (enabledevts
&evt
.EnumType
) == evt
.EnumType
)
43 context
->EventCb(evt
.u
.user
.type
, evt
.u
.user
.id
, evt
.u
.user
.param
,
44 (ALsizei
)strlen(evt
.u
.user
.msg
), evt
.u
.user
.msg
, context
->EventParam
46 } while(ll_ringbuffer_read(context
->AsyncEvents
, &evt
, 1) != 0);
51 void StartEventThrd(ALCcontext
*ctx
)
54 ctx
->EventThread
= std::thread(EventThread
, ctx
);
56 catch(std::exception
& e
) {
57 ERR("Failed to start event thread: %s\n", e
.what());
60 ERR("Failed to start event thread! Expect problems.\n");
64 void StopEventThrd(ALCcontext
*ctx
)
66 static constexpr AsyncEvent kill_evt
= ASYNC_EVENT(EventType_KillThread
);
67 while(ll_ringbuffer_write(ctx
->AsyncEvents
, &kill_evt
, 1) == 0)
69 alsem_post(&ctx
->EventSem
);
70 if(ctx
->EventThread
.joinable())
71 ctx
->EventThread
.join();
74 AL_API
void AL_APIENTRY
alEventControlSOFT(ALsizei count
, const ALenum
*types
, ALboolean enable
)
76 ContextRef context
{GetContextRef()};
77 if(UNLIKELY(!context
)) return;
79 if(count
< 0) SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Controlling %d events", count
);
80 if(count
== 0) return;
81 if(!types
) SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "NULL pointer");
83 ALbitfieldSOFT flags
{0};
84 const ALenum
*types_end
= types
+count
;
85 auto bad_type
= std::find_if_not(types
, types_end
,
86 [&flags
](ALenum type
) noexcept
-> bool
88 if(type
== AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
)
89 flags
|= EventType_BufferCompleted
;
90 else if(type
== AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
)
91 flags
|= EventType_SourceStateChange
;
92 else if(type
== AL_EVENT_TYPE_ERROR_SOFT
)
93 flags
|= EventType_Error
;
94 else if(type
== AL_EVENT_TYPE_PERFORMANCE_SOFT
)
95 flags
|= EventType_Performance
;
96 else if(type
== AL_EVENT_TYPE_DEPRECATED_SOFT
)
97 flags
|= EventType_Deprecated
;
98 else if(type
== AL_EVENT_TYPE_DISCONNECTED_SOFT
)
99 flags
|= EventType_Disconnected
;
105 if(bad_type
!= types_end
)
106 SETERR_RETURN(context
.get(), AL_INVALID_ENUM
,, "Invalid event type 0x%04x", *bad_type
);
110 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_relaxed
)};
111 while(context
->EnabledEvts
.compare_exchange_weak(enabledevts
, enabledevts
|flags
,
112 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0)
114 /* enabledevts is (re-)filled with the current value on failure, so
121 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_relaxed
)};
122 while(context
->EnabledEvts
.compare_exchange_weak(enabledevts
, enabledevts
&~flags
,
123 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0)
126 /* Wait to ensure the event handler sees the changed flags before
129 std::lock_guard
<std::mutex
>{context
->EventCbLock
};
133 AL_API
void AL_APIENTRY
alEventCallbackSOFT(ALEVENTPROCSOFT callback
, void *userParam
)
135 ContextRef context
{GetContextRef()};
136 if(UNLIKELY(!context
)) return;
138 std::lock_guard
<almtx_t
> _
{context
->PropLock
};
139 std::lock_guard
<std::mutex
> __
{context
->EventCbLock
};
140 context
->EventCb
= callback
;
141 context
->EventParam
= userParam
;