Fix compilation with older alext.h headers
[alure.git] / src / context.h
blob7ea052e5669c57a6f96dd4db797c4a8a6cd81335
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 "device.h"
24 #include "source.h"
27 extern "C" {
28 #ifndef AL_SOFT_source_latency
29 #define AL_SOFT_source_latency 1
30 #define AL_SAMPLE_OFFSET_LATENCY_SOFT 0x1200
31 #define AL_SEC_OFFSET_LATENCY_SOFT 0x1201
32 typedef int64_t ALint64SOFT;
33 typedef uint64_t ALuint64SOFT;
34 typedef void (AL_APIENTRY*LPALSOURCEDSOFT)(ALuint,ALenum,ALdouble);
35 typedef void (AL_APIENTRY*LPALSOURCE3DSOFT)(ALuint,ALenum,ALdouble,ALdouble,ALdouble);
36 typedef void (AL_APIENTRY*LPALSOURCEDVSOFT)(ALuint,ALenum,const ALdouble*);
37 typedef void (AL_APIENTRY*LPALGETSOURCEDSOFT)(ALuint,ALenum,ALdouble*);
38 typedef void (AL_APIENTRY*LPALGETSOURCE3DSOFT)(ALuint,ALenum,ALdouble*,ALdouble*,ALdouble*);
39 typedef void (AL_APIENTRY*LPALGETSOURCEDVSOFT)(ALuint,ALenum,ALdouble*);
40 typedef void (AL_APIENTRY*LPALSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT);
41 typedef void (AL_APIENTRY*LPALSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT,ALint64SOFT,ALint64SOFT);
42 typedef void (AL_APIENTRY*LPALSOURCEI64VSOFT)(ALuint,ALenum,const ALint64SOFT*);
43 typedef void (AL_APIENTRY*LPALGETSOURCEI64SOFT)(ALuint,ALenum,ALint64SOFT*);
44 typedef void (AL_APIENTRY*LPALGETSOURCE3I64SOFT)(ALuint,ALenum,ALint64SOFT*,ALint64SOFT*,ALint64SOFT*);
45 typedef void (AL_APIENTRY*LPALGETSOURCEI64VSOFT)(ALuint,ALenum,ALint64SOFT*);
46 #endif
48 #ifndef AL_SOFT_source_resampler
49 #define AL_SOFT_source_resampler
50 #define AL_NUM_RESAMPLERS_SOFT 0x1210
51 #define AL_DEFAULT_RESAMPLER_SOFT 0x1211
52 #define AL_SOURCE_RESAMPLER_SOFT 0x1212
53 #define AL_RESAMPLER_NAME_SOFT 0x1213
54 typedef const ALchar* (AL_APIENTRY*LPALGETSTRINGISOFT)(ALenum pname, ALsizei index);
55 #endif
57 #ifndef AL_SOFT_source_spatialize
58 #define AL_SOFT_source_spatialize
59 #define AL_SOURCE_SPATIALIZE_SOFT 0x1214
60 #define AL_AUTO_SOFT 0x0002
61 #endif
62 } // extern "C"
64 #define F_PI (3.14159265358979323846f)
66 #if !(__cplusplus >= 201703L)
67 namespace std {
68 using mpark::variant;
69 using mpark::get;
70 using mpark::get_if;
71 using mpark::holds_alternative;
72 } // namespace std
73 #endif
75 namespace alure {
77 enum class AL {
78 EXT_EFX,
80 EXT_FLOAT32,
81 EXT_MCFORMATS,
82 EXT_BFORMAT,
84 EXT_MULAW,
85 EXT_MULAW_MCFORMATS,
86 EXT_MULAW_BFORMAT,
88 SOFT_loop_points,
89 SOFT_source_latency,
90 SOFT_source_resampler,
91 SOFT_source_spatialize,
93 EXT_disconnect,
95 EXT_SOURCE_RADIUS,
96 EXT_STEREO_ANGLES,
98 EXTENSION_MAX
101 // Batches OpenAL updates while the object is alive, if batching isn't already
102 // in progress.
103 class Batcher {
104 ALCcontext *mContext;
106 public:
107 Batcher(ALCcontext *context) : mContext(context) { }
108 Batcher(Batcher&& rhs) : mContext(rhs.mContext) { rhs.mContext = nullptr; }
109 Batcher(const Batcher&) = delete;
110 ~Batcher()
112 if(mContext)
113 alcProcessContext(mContext);
116 Batcher& operator=(Batcher&&) = delete;
117 Batcher& operator=(const Batcher&) = delete;
121 class ListenerImpl {
122 ContextImpl *const mContext;
124 public:
125 ListenerImpl(ContextImpl *ctx) : mContext(ctx) { }
127 void setGain(ALfloat gain);
129 void set3DParameters(const Vector3 &position, const Vector3 &velocity, const std::pair<Vector3,Vector3> &orientation);
131 void setPosition(ALfloat x, ALfloat y, ALfloat z);
132 void setPosition(const ALfloat *pos);
134 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
135 void setVelocity(const ALfloat *vel);
137 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
138 void setOrientation(const ALfloat *at, const ALfloat *up);
139 void setOrientation(const ALfloat *ori);
141 void setMetersPerUnit(ALfloat m_u);
145 using DecoderOrExceptT = std::variant<SharedPtr<Decoder>,std::runtime_error>;
146 using BufferOrExceptT = std::variant<Buffer,std::runtime_error>;
148 class ContextImpl {
149 static ContextImpl *sCurrentCtx;
150 static thread_local ContextImpl *sThreadCurrentCtx;
152 public:
153 static void MakeCurrent(ContextImpl *context);
154 static ContextImpl *GetCurrent()
156 auto thrd_ctx = sThreadCurrentCtx;
157 return thrd_ctx ? thrd_ctx : sCurrentCtx;
160 static void MakeThreadCurrent(ContextImpl *context);
161 static ContextImpl *GetThreadCurrent() { return sThreadCurrentCtx; }
163 static std::atomic<uint64_t> sContextSetCount;
164 mutable uint64_t mContextSetCounter;
166 private:
167 ListenerImpl mListener;
168 ALCcontext *mContext;
169 std::stack<ALuint> mSourceIds;
171 struct PendingFuture { BufferImpl *mBuffer; SharedFuture<Buffer> mFuture; };
172 struct PendingSource { SourceImpl *mSource; SharedFuture<Buffer> mFuture; };
174 DeviceImpl *const mDevice;
175 Vector<PendingFuture> mFutureBuffers;
176 Vector<UniquePtr<BufferImpl>> mBuffers;
177 Vector<UniquePtr<SourceGroupImpl>> mSourceGroups;
178 std::deque<SourceImpl> mAllSources;
179 Vector<SourceImpl*> mFreeSources;
181 Vector<PendingSource> mPendingSources;
182 Vector<SourceImpl*> mFadingSources;
183 Vector<SourceBufferUpdateEntry> mPlaySources;
184 Vector<SourceStreamUpdateEntry> mStreamSources;
186 Vector<SourceImpl*> mStreamingSources;
187 std::mutex mSourceStreamMutex;
189 std::atomic<std::chrono::milliseconds> mWakeInterval;
190 std::mutex mWakeMutex;
191 std::condition_variable mWakeThread;
193 SharedPtr<MessageHandler> mMessage;
195 struct PendingBuffer {
196 BufferImpl *mBuffer{nullptr};
197 SharedPtr<Decoder> mDecoder;
198 ALenum mFormat{0};
199 ALuint mFrames{0};
200 Promise<Buffer> mPromise;
202 std::atomic<PendingBuffer*> mNext{nullptr};
204 PendingBuffer() = default;
205 PendingBuffer(BufferImpl *buffer, SharedPtr<Decoder> decoder, ALenum format, ALuint frames,
206 Promise<Buffer> promise)
207 : mBuffer(buffer), mDecoder(std::move(decoder)), mFormat(format), mFrames(frames)
208 , mPromise(std::move(promise)), mNext(nullptr)
211 std::atomic<PendingBuffer*> mPendingCurrent;
212 PendingBuffer *mPendingTail;
213 PendingBuffer *mPendingHead;
215 std::atomic<bool> mQuitThread;
216 std::thread mThread;
217 void backgroundProc();
219 size_t mRefs;
221 Vector<String> mResamplers;
223 Bitfield<static_cast<size_t>(AL::EXTENSION_MAX)> mHasExt;
225 std::once_flag mSetExts;
226 void setupExts();
228 DecoderOrExceptT findDecoder(StringView name);
229 BufferOrExceptT doCreateBuffer(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder);
230 BufferOrExceptT doCreateBufferAsync(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder, Promise<Buffer> promise);
232 bool mIsConnected : 1;
233 bool mIsBatching : 1;
235 public:
236 ContextImpl(ALCcontext *context, DeviceImpl *device);
237 ~ContextImpl();
239 ALCcontext *getALCcontext() const { return mContext; }
240 long addRef() { return ++mRefs; }
241 long decRef() { return --mRefs; }
243 bool hasExtension(AL ext) const { return mHasExt[static_cast<size_t>(ext)]; }
245 LPALGETSTRINGISOFT alGetStringiSOFT;
246 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
247 LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
249 LPALGENEFFECTS alGenEffects;
250 LPALDELETEEFFECTS alDeleteEffects;
251 LPALISEFFECT alIsEffect;
252 LPALEFFECTI alEffecti;
253 LPALEFFECTIV alEffectiv;
254 LPALEFFECTF alEffectf;
255 LPALEFFECTFV alEffectfv;
256 LPALGETEFFECTI alGetEffecti;
257 LPALGETEFFECTIV alGetEffectiv;
258 LPALGETEFFECTF alGetEffectf;
259 LPALGETEFFECTFV alGetEffectfv;
261 LPALGENFILTERS alGenFilters;
262 LPALDELETEFILTERS alDeleteFilters;
263 LPALISFILTER alIsFilter;
264 LPALFILTERI alFilteri;
265 LPALFILTERIV alFilteriv;
266 LPALFILTERF alFilterf;
267 LPALFILTERFV alFilterfv;
268 LPALGETFILTERI alGetFilteri;
269 LPALGETFILTERIV alGetFilteriv;
270 LPALGETFILTERF alGetFilterf;
271 LPALGETFILTERFV alGetFilterfv;
273 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
274 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
275 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
276 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
277 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
278 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
279 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
280 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
281 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
282 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
283 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
285 ALuint getSourceId(ALuint maxprio);
286 void insertSourceId(ALuint id) { mSourceIds.push(id); }
288 void addPendingSource(SourceImpl *source, SharedFuture<Buffer> future);
289 void removePendingSource(SourceImpl *source);
290 bool isPendingSource(const SourceImpl *source) const;
291 void addFadingSource(SourceImpl *source);
292 void removeFadingSource(SourceImpl *source);
293 void addPlayingSource(SourceImpl *source, ALuint id);
294 void addPlayingSource(SourceImpl *source);
295 void removePlayingSource(SourceImpl *source);
297 void addStream(SourceImpl *source);
298 void removeStream(SourceImpl *source);
299 void removeStreamNoLock(SourceImpl *source);
301 void freeSource(SourceImpl *source) { mFreeSources.push_back(source); }
302 void freeSourceGroup(SourceGroupImpl *group);
304 Batcher getBatcher()
306 if(mIsBatching)
307 return Batcher(nullptr);
308 alcSuspendContext(mContext);
309 return Batcher(mContext);
312 std::unique_lock<std::mutex> getSourceStreamLock()
313 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
315 template<typename R, typename... Args>
316 void send(R MessageHandler::* func, Args&&... args)
317 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
319 Device getDevice() { return Device(mDevice); }
321 void destroy();
323 void startBatch();
324 void endBatch();
326 Listener getListener() { return Listener(&mListener); }
328 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler>&& handler);
329 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
331 void setAsyncWakeInterval(std::chrono::milliseconds interval);
332 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
334 SharedPtr<Decoder> createDecoder(StringView name);
336 bool isSupported(ChannelConfig channels, SampleType type) const;
338 ArrayView<String> getAvailableResamplers();
339 ALsizei getDefaultResamplerIndex() const;
341 Buffer getBuffer(StringView name);
342 SharedFuture<Buffer> getBufferAsync(StringView name);
343 void precacheBuffersAsync(ArrayView<StringView> names);
344 Buffer createBufferFrom(StringView name, SharedPtr<Decoder>&& decoder);
345 SharedFuture<Buffer> createBufferAsyncFrom(StringView name, SharedPtr<Decoder>&& decoder);
346 void removeBuffer(StringView name);
347 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
349 Source createSource();
351 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
353 Effect createEffect();
355 SourceGroup createSourceGroup(StringView name);
356 SourceGroup getSourceGroup(StringView name);
358 void setDopplerFactor(ALfloat factor);
360 void setSpeedOfSound(ALfloat speed);
362 void setDistanceModel(DistanceModel model);
364 void update();
368 inline void CheckContext(const ContextImpl *ctx)
370 auto count = ContextImpl::sContextSetCount.load(std::memory_order_acquire);
371 if(UNLIKELY(count != ctx->mContextSetCounter))
373 if(UNLIKELY(ctx != ContextImpl::GetCurrent()))
374 throw std::runtime_error("Called context is not current");
375 ctx->mContextSetCounter = count;
379 inline void CheckContexts(const ContextImpl *ctx0, const ContextImpl *ctx1)
381 if(UNLIKELY(ctx0 != ctx1))
382 throw std::runtime_error("Mismatched object contexts");
386 } // namespace alure
388 #endif /* CONTEXT_H */