Use a separate function to remove a source from fading sources
[alure.git] / src / context.h
blobcfc291c5ea264d28746b6667ace8e97f7f3bf28f
1 #ifndef CONTEXT_H
2 #define CONTEXT_H
4 #include "main.h"
6 #include <condition_variable>
7 #include <unordered_map>
8 #include <stdexcept>
9 #include <thread>
10 #include <mutex>
11 #include <stack>
12 #include <queue>
13 #include <set>
14 #if __cplusplus >= 201703L
15 #include <variant>
16 #else
17 #include "mpark/variant.hpp"
18 #endif
20 #include "alc.h"
21 #include "alext.h"
23 #include "refcount.h"
24 #include "device.h"
25 #include "source.h"
27 #define F_PI (3.14159265358979323846f)
29 #if !(__cplusplus >= 201703L)
30 namespace std {
31 using mpark::variant;
32 using mpark::get;
33 using mpark::get_if;
34 using mpark::holds_alternative;
35 } // namespace std
36 #endif
38 namespace alure {
40 enum ALExtension {
41 EXT_EFX,
43 EXT_FLOAT32,
44 EXT_MCFORMATS,
45 EXT_BFORMAT,
47 EXT_MULAW,
48 EXT_MULAW_MCFORMATS,
49 EXT_MULAW_BFORMAT,
51 SOFT_loop_points,
52 SOFT_source_latency,
53 SOFT_source_resampler,
54 SOFT_source_spatialize,
56 EXT_disconnect,
58 EXT_SOURCE_RADIUS,
59 EXT_STEREO_ANGLES,
61 AL_EXTENSION_MAX
64 // Batches OpenAL updates while the object is alive, if batching isn't already
65 // in progress.
66 class Batcher {
67 ALCcontext *mContext;
69 public:
70 Batcher(ALCcontext *context) : mContext(context) { }
71 Batcher(Batcher&& rhs) : mContext(rhs.mContext) { rhs.mContext = nullptr; }
72 Batcher(const Batcher&) = delete;
73 ~Batcher()
75 if(mContext)
76 alcProcessContext(mContext);
79 Batcher& operator=(Batcher&&) = delete;
80 Batcher& operator=(const Batcher&) = delete;
84 class ListenerImpl {
85 ContextImpl *const mContext;
87 public:
88 ListenerImpl(ContextImpl *ctx) : mContext(ctx) { }
90 void setGain(ALfloat gain);
92 void set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation);
94 void setPosition(ALfloat x, ALfloat y, ALfloat z);
95 void setPosition(const ALfloat *pos);
97 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
98 void setVelocity(const ALfloat *vel);
100 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
101 void setOrientation(const ALfloat *at, const ALfloat *up);
102 void setOrientation(const ALfloat *ori);
104 void setMetersPerUnit(ALfloat m_u);
108 using DecoderOrExceptT = std::variant<SharedPtr<Decoder>,std::runtime_error>;
109 using BufferOrExceptT = std::variant<Buffer,std::runtime_error>;
111 class ContextImpl {
112 static ContextImpl *sCurrentCtx;
113 static thread_local ContextImpl *sThreadCurrentCtx;
115 public:
116 static void MakeCurrent(ContextImpl *context);
117 static ContextImpl *GetCurrent() { return sThreadCurrentCtx ? sThreadCurrentCtx : sCurrentCtx; }
119 static void MakeThreadCurrent(ContextImpl *context);
120 static ContextImpl *GetThreadCurrent() { return sThreadCurrentCtx; }
122 private:
123 ListenerImpl mListener;
124 ALCcontext *mContext;
125 std::stack<ALuint> mSourceIds;
127 struct PendingFuture { BufferImpl *mBuffer; SharedFuture<Buffer> mFuture; };
129 DeviceImpl *const mDevice;
130 Vector<PendingFuture> mFutureBuffers;
131 Vector<UniquePtr<BufferImpl>> mBuffers;
132 Vector<UniquePtr<SourceGroupImpl>> mSourceGroups;
133 std::deque<SourceImpl> mAllSources;
134 Vector<SourceImpl*> mFreeSources;
135 Vector<SourceBufferUpdateEntry> mPlaySources;
136 Vector<SourceStreamUpdateEntry> mStreamSources;
137 Vector<SourceImpl*> mFadingSources;
139 Vector<SourceImpl*> mStreamingSources;
140 std::mutex mSourceStreamMutex;
142 std::atomic<std::chrono::milliseconds> mWakeInterval;
143 std::mutex mWakeMutex;
144 std::condition_variable mWakeThread;
146 SharedPtr<MessageHandler> mMessage;
148 struct PendingBuffer {
149 BufferImpl *mBuffer{nullptr};
150 SharedPtr<Decoder> mDecoder;
151 ALenum mFormat{0};
152 ALuint mFrames{0};
153 Promise<Buffer> mPromise;
155 std::atomic<PendingBuffer*> mNext{nullptr};
157 PendingBuffer() = default;
158 PendingBuffer(BufferImpl *buffer, SharedPtr<Decoder> decoder, ALenum format, ALuint frames,
159 Promise<Buffer> promise)
160 : mBuffer(buffer), mDecoder(std::move(decoder)), mFormat(format), mFrames(frames)
161 , mPromise(std::move(promise)), mNext(nullptr)
164 std::atomic<PendingBuffer*> mPendingCurrent;
165 PendingBuffer *mPendingTail;
166 PendingBuffer *mPendingHead;
168 std::atomic<bool> mQuitThread;
169 std::thread mThread;
170 void backgroundProc();
172 RefCount mRefs;
174 Vector<String> mResamplers;
176 bool mHasExt[AL_EXTENSION_MAX];
178 std::once_flag mSetExts;
179 void setupExts();
181 DecoderOrExceptT findDecoder(StringView name);
182 BufferOrExceptT doCreateBuffer(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder);
183 BufferOrExceptT doCreateBufferAsync(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder, Promise<Buffer> promise);
185 bool mIsConnected : 1;
186 bool mIsBatching : 1;
188 public:
189 ContextImpl(ALCcontext *context, DeviceImpl *device);
190 ~ContextImpl();
192 ALCcontext *getContext() const { return mContext; }
193 long addRef() { return ++mRefs; }
194 long decRef() { return --mRefs; }
196 bool hasExtension(ALExtension ext) const { return mHasExt[ext]; }
198 LPALGETSTRINGISOFT alGetStringiSOFT;
199 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
200 LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
202 LPALGENEFFECTS alGenEffects;
203 LPALDELETEEFFECTS alDeleteEffects;
204 LPALISEFFECT alIsEffect;
205 LPALEFFECTI alEffecti;
206 LPALEFFECTIV alEffectiv;
207 LPALEFFECTF alEffectf;
208 LPALEFFECTFV alEffectfv;
209 LPALGETEFFECTI alGetEffecti;
210 LPALGETEFFECTIV alGetEffectiv;
211 LPALGETEFFECTF alGetEffectf;
212 LPALGETEFFECTFV alGetEffectfv;
214 LPALGENFILTERS alGenFilters;
215 LPALDELETEFILTERS alDeleteFilters;
216 LPALISFILTER alIsFilter;
217 LPALFILTERI alFilteri;
218 LPALFILTERIV alFilteriv;
219 LPALFILTERF alFilterf;
220 LPALFILTERFV alFilterfv;
221 LPALGETFILTERI alGetFilteri;
222 LPALGETFILTERIV alGetFilteriv;
223 LPALGETFILTERF alGetFilterf;
224 LPALGETFILTERFV alGetFilterfv;
226 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
227 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
228 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
229 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
230 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
231 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
232 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
233 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
234 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
235 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
236 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
238 ALuint getSourceId(ALuint maxprio);
239 void insertSourceId(ALuint id) { mSourceIds.push(id); }
241 void addFadingSource(SourceImpl *source);
242 void removeFadingSource(SourceImpl *source);
243 void addPlayingSource(SourceImpl *source, ALuint id);
244 void addPlayingSource(SourceImpl *source);
245 void removePlayingSource(SourceImpl *source);
247 void addStream(SourceImpl *source);
248 void removeStream(SourceImpl *source);
249 void removeStreamNoLock(SourceImpl *source);
251 void freeSource(SourceImpl *source) { mFreeSources.push_back(source); }
252 void freeSourceGroup(SourceGroupImpl *group);
254 Batcher getBatcher()
256 if(mIsBatching)
257 return Batcher(nullptr);
258 alcSuspendContext(mContext);
259 return Batcher(mContext);
262 std::unique_lock<std::mutex> getSourceStreamLock()
263 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
265 template<typename R, typename... Args>
266 void send(R MessageHandler::* func, Args&&... args)
267 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
269 Device getDevice() { return Device(mDevice); }
271 void destroy();
273 void startBatch();
274 void endBatch();
276 Listener getListener() { return Listener(&mListener); }
278 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler> handler);
279 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
281 void setAsyncWakeInterval(std::chrono::milliseconds interval);
282 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
284 SharedPtr<Decoder> createDecoder(StringView name);
286 bool isSupported(ChannelConfig channels, SampleType type) const;
288 ArrayView<String> getAvailableResamplers();
289 ALsizei getDefaultResamplerIndex() const;
291 Buffer getBuffer(StringView name);
292 SharedFuture<Buffer> getBufferAsync(StringView name);
293 void precacheBuffersAsync(ArrayView<StringView> names);
294 Buffer createBufferFrom(StringView name, SharedPtr<Decoder> decoder);
295 SharedFuture<Buffer> createBufferAsyncFrom(StringView name, SharedPtr<Decoder> decoder);
296 void removeBuffer(StringView name);
297 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
299 Source createSource();
301 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
303 Effect createEffect();
305 SourceGroup createSourceGroup(StringView name);
306 SourceGroup getSourceGroup(StringView name);
308 void setDopplerFactor(ALfloat factor);
310 void setSpeedOfSound(ALfloat speed);
312 void setDistanceModel(DistanceModel model);
314 void update();
318 inline void CheckContext(const ContextImpl *ctx)
320 if(Expect<false>(ctx != ContextImpl::GetCurrent()))
321 throw std::runtime_error("Called context is not current");
324 } // namespace alure
326 #endif /* CONTEXT_H */