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 context
->EventSem
.wait();
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
) continue;
44 if(evt
.EnumType
== EventType_SourceStateChange
)
46 if(!(enabledevts
&EventType_SourceStateChange
))
48 std::string msg
{"Source ID " + std::to_string(evt
.u
.srcstate
.id
)};
49 msg
+= " state has changed to ";
50 msg
+= (evt
.u
.srcstate
.state
==AL_INITIAL
) ? "AL_INITIAL" :
51 (evt
.u
.srcstate
.state
==AL_PLAYING
) ? "AL_PLAYING" :
52 (evt
.u
.srcstate
.state
==AL_PAUSED
) ? "AL_PAUSED" :
53 (evt
.u
.srcstate
.state
==AL_STOPPED
) ? "AL_STOPPED" : "<unknown>";
54 context
->EventCb(AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
, evt
.u
.srcstate
.id
,
55 evt
.u
.srcstate
.state
, msg
.length(), msg
.c_str(), context
->EventParam
58 else if(evt
.EnumType
== EventType_BufferCompleted
)
60 if(!(enabledevts
&EventType_BufferCompleted
))
62 std::string msg
{std::to_string(evt
.u
.bufcomp
.count
)};
63 if(evt
.u
.bufcomp
.count
== 1) msg
+= " buffer completed";
64 else msg
+= " buffers completed";
65 context
->EventCb(AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
, evt
.u
.bufcomp
.id
,
66 evt
.u
.bufcomp
.count
, msg
.length(), msg
.c_str(), context
->EventParam
69 else if((enabledevts
&evt
.EnumType
) == evt
.EnumType
)
70 context
->EventCb(evt
.u
.user
.type
, evt
.u
.user
.id
, evt
.u
.user
.param
,
71 (ALsizei
)strlen(evt
.u
.user
.msg
), evt
.u
.user
.msg
, context
->EventParam
73 } while(ll_ringbuffer_read(context
->AsyncEvents
, &evt
, 1) != 0);
78 void StartEventThrd(ALCcontext
*ctx
)
81 ctx
->EventThread
= std::thread(EventThread
, ctx
);
83 catch(std::exception
& e
) {
84 ERR("Failed to start event thread: %s\n", e
.what());
87 ERR("Failed to start event thread! Expect problems.\n");
91 void StopEventThrd(ALCcontext
*ctx
)
93 static constexpr AsyncEvent kill_evt
= ASYNC_EVENT(EventType_KillThread
);
94 while(ll_ringbuffer_write(ctx
->AsyncEvents
, &kill_evt
, 1) == 0)
95 std::this_thread::yield();
97 if(ctx
->EventThread
.joinable())
98 ctx
->EventThread
.join();
101 AL_API
void AL_APIENTRY
alEventControlSOFT(ALsizei count
, const ALenum
*types
, ALboolean enable
)
103 ContextRef context
{GetContextRef()};
104 if(UNLIKELY(!context
)) return;
106 if(count
< 0) SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "Controlling %d events", count
);
107 if(count
== 0) return;
108 if(!types
) SETERR_RETURN(context
.get(), AL_INVALID_VALUE
,, "NULL pointer");
110 ALbitfieldSOFT flags
{0};
111 const ALenum
*types_end
= types
+count
;
112 auto bad_type
= std::find_if_not(types
, types_end
,
113 [&flags
](ALenum type
) noexcept
-> bool
115 if(type
== AL_EVENT_TYPE_BUFFER_COMPLETED_SOFT
)
116 flags
|= EventType_BufferCompleted
;
117 else if(type
== AL_EVENT_TYPE_SOURCE_STATE_CHANGED_SOFT
)
118 flags
|= EventType_SourceStateChange
;
119 else if(type
== AL_EVENT_TYPE_ERROR_SOFT
)
120 flags
|= EventType_Error
;
121 else if(type
== AL_EVENT_TYPE_PERFORMANCE_SOFT
)
122 flags
|= EventType_Performance
;
123 else if(type
== AL_EVENT_TYPE_DEPRECATED_SOFT
)
124 flags
|= EventType_Deprecated
;
125 else if(type
== AL_EVENT_TYPE_DISCONNECTED_SOFT
)
126 flags
|= EventType_Disconnected
;
132 if(bad_type
!= types_end
)
133 SETERR_RETURN(context
.get(), AL_INVALID_ENUM
,, "Invalid event type 0x%04x", *bad_type
);
137 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_relaxed
)};
138 while(context
->EnabledEvts
.compare_exchange_weak(enabledevts
, enabledevts
|flags
,
139 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0)
141 /* enabledevts is (re-)filled with the current value on failure, so
148 ALbitfieldSOFT enabledevts
{context
->EnabledEvts
.load(std::memory_order_relaxed
)};
149 while(context
->EnabledEvts
.compare_exchange_weak(enabledevts
, enabledevts
&~flags
,
150 std::memory_order_acq_rel
, std::memory_order_acquire
) == 0)
153 /* Wait to ensure the event handler sees the changed flags before
156 std::lock_guard
<std::mutex
>{context
->EventCbLock
};
160 AL_API
void AL_APIENTRY
alEventCallbackSOFT(ALEVENTPROCSOFT callback
, void *userParam
)
162 ContextRef context
{GetContextRef()};
163 if(UNLIKELY(!context
)) return;
165 std::lock_guard
<std::mutex
> _
{context
->PropLock
};
166 std::lock_guard
<std::mutex
> __
{context
->EventCbLock
};
167 context
->EventCb
= callback
;
168 context
->EventParam
= userParam
;