Merge pull request #40 from McSinyx/travis
[alure.git] / src / context.h
blobdee1a2cf39fd1abec9810e8894ab9cf6f50d5c44
1 #ifndef CONTEXT_H
2 #define CONTEXT_H
4 #include <condition_variable>
5 #include <unordered_map>
6 #include <stdexcept>
7 #include <thread>
8 #include <mutex>
9 #include <stack>
10 #include <queue>
11 #include <set>
13 #include "main.h"
15 #include "device.h"
16 #include "source.h"
19 #define F_PI (3.14159265358979323846f)
21 namespace alure {
23 enum class AL {
24 EXT_EFX,
26 EXT_FLOAT32,
27 EXT_MCFORMATS,
28 EXT_BFORMAT,
30 EXT_MULAW,
31 EXT_MULAW_MCFORMATS,
32 EXT_MULAW_BFORMAT,
34 SOFT_loop_points,
35 SOFT_source_latency,
36 SOFT_source_resampler,
37 SOFT_source_spatialize,
39 EXT_disconnect,
41 EXT_SOURCE_RADIUS,
42 EXT_STEREO_ANGLES,
44 EXTENSION_MAX
47 // Batches OpenAL updates while the object is alive, if batching isn't already
48 // in progress.
49 class Batcher {
50 ALCcontext *mContext;
52 public:
53 Batcher(ALCcontext *context) : mContext(context) { }
54 Batcher(Batcher&& rhs) : mContext(rhs.mContext) { rhs.mContext = nullptr; }
55 Batcher(const Batcher&) = delete;
56 ~Batcher()
58 if(mContext)
59 alcProcessContext(mContext);
62 Batcher& operator=(Batcher&&) = delete;
63 Batcher& operator=(const Batcher&) = delete;
67 class ListenerImpl {
68 ContextImpl *const mContext;
70 public:
71 ListenerImpl(ContextImpl *ctx) : mContext(ctx) { }
73 void setGain(ALfloat gain);
75 void set3DParameters(const Vector3 &position, const Vector3 &velocity, const std::pair<Vector3,Vector3> &orientation);
77 void setPosition(const Vector3 &position);
78 void setPosition(const ALfloat *pos);
80 void setVelocity(const Vector3 &velocity);
81 void setVelocity(const ALfloat *vel);
83 void setOrientation(const std::pair<Vector3,Vector3> &orientation);
84 void setOrientation(const ALfloat *at, const ALfloat *up);
85 void setOrientation(const ALfloat *ori);
87 void setMetersPerUnit(ALfloat m_u);
91 using DecoderOrExceptT = std::variant<SharedPtr<Decoder>,std::exception_ptr>;
92 using BufferOrExceptT = std::variant<Buffer,std::exception_ptr>;
94 class ContextImpl {
95 static ContextImpl *sCurrentCtx;
96 static thread_local ContextImpl *sThreadCurrentCtx;
98 public:
99 static void MakeCurrent(ContextImpl *context);
100 static ContextImpl *GetCurrent()
102 auto thrd_ctx = sThreadCurrentCtx;
103 return thrd_ctx ? thrd_ctx : sCurrentCtx;
106 static void MakeThreadCurrent(ContextImpl *context);
107 static ContextImpl *GetThreadCurrent() { return sThreadCurrentCtx; }
109 static std::atomic<uint64_t> sContextSetCount;
110 mutable uint64_t mContextSetCounter{std::numeric_limits<uint64_t>::max()};
112 struct ContextDeleter {
113 void operator()(ALCcontext *ptr) const { alcDestroyContext(ptr); }
115 using ContextPtr = UniquePtr<ALCcontext,ContextDeleter>;
117 private:
118 ListenerImpl mListener;
120 ContextPtr mContext;
121 Vector<ALuint> mSourceIds;
123 struct PendingBuffer { BufferImpl *mBuffer; SharedFuture<Buffer> mFuture; };
124 struct PendingSource { SourceImpl *mSource; SharedFuture<Buffer> mFuture; };
125 using BufferListT = Vector<UniquePtr<BufferImpl>>;
126 using FutureBufferListT = Vector<PendingBuffer>;
128 DeviceImpl &mDevice;
129 FutureBufferListT mFutureBuffers;
130 BufferListT mBuffers;
131 Vector<UniquePtr<SourceGroupImpl>> mSourceGroups;
132 Vector<UniquePtr<AuxiliaryEffectSlotImpl>> mEffectSlots;
133 Vector<UniquePtr<EffectImpl>> mEffects;
134 std::deque<SourceImpl> mAllSources;
135 Vector<SourceImpl*> mFreeSources;
137 Vector<PendingSource> mPendingSources;
138 Vector<SourceFadeUpdateEntry> mFadingSources;
139 Vector<SourceBufferUpdateEntry> mPlaySources;
140 Vector<SourceStreamUpdateEntry> mStreamSources;
142 Vector<SourceImpl*> mStreamingSources;
143 std::mutex mSourceStreamMutex;
145 std::atomic<std::chrono::milliseconds> mWakeInterval{std::chrono::milliseconds::zero()};
146 std::mutex mWakeMutex;
147 std::condition_variable mWakeThread;
149 SharedPtr<MessageHandler> mMessage;
151 struct PendingPromise {
152 BufferImpl *mBuffer{nullptr};
153 SharedPtr<Decoder> mDecoder;
154 ALenum mFormat{AL_NONE};
155 ALuint mFrames{0};
156 Promise<Buffer> mPromise;
158 std::atomic<PendingPromise*> mNext{nullptr};
160 PendingPromise() = default;
161 PendingPromise(BufferImpl *buffer, SharedPtr<Decoder> decoder, ALenum format,
162 ALuint frames, Promise<Buffer> promise)
163 : mBuffer(buffer), mDecoder(std::move(decoder)), mFormat(format), mFrames(frames)
164 , mPromise(std::move(promise))
167 std::atomic<PendingPromise*> mPendingCurrent{nullptr};
168 PendingPromise *mPendingTail{nullptr};
169 PendingPromise *mPendingHead{nullptr};
171 std::atomic<bool> mQuitThread{false};
172 std::thread mThread;
173 void backgroundProc();
175 size_t mRefs{0};
177 Vector<String> mResamplers;
179 Bitfield<static_cast<size_t>(AL::EXTENSION_MAX)> mHasExt;
181 std::once_flag mSetExts;
182 void setupExts();
184 DecoderOrExceptT findDecoder(StringView name);
185 BufferOrExceptT doCreateBuffer(StringView name, size_t name_hash, BufferListT::const_iterator iter, SharedPtr<Decoder> decoder);
186 BufferOrExceptT doCreateBufferAsync(StringView name, size_t name_hash, BufferListT::const_iterator iter, SharedPtr<Decoder> decoder, Promise<Buffer> promise);
188 bool mIsConnected : 1;
189 bool mIsBatching : 1;
191 public:
192 ContextImpl(DeviceImpl &device, ArrayView<AttributePair> attrs);
193 ~ContextImpl();
195 ALCcontext *getALCcontext() const { return mContext.get(); }
196 size_t addRef() { return ++mRefs; }
197 size_t decRef() { return --mRefs; }
199 bool hasExtension(AL ext) const { return mHasExt[static_cast<size_t>(ext)]; }
201 LPALGETSTRINGISOFT alGetStringiSOFT{nullptr};
202 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT{nullptr};
203 LPALGETSOURCEDVSOFT alGetSourcedvSOFT{nullptr};
205 LPALGENEFFECTS alGenEffects{nullptr};
206 LPALDELETEEFFECTS alDeleteEffects{nullptr};
207 LPALISEFFECT alIsEffect{nullptr};
208 LPALEFFECTI alEffecti{nullptr};
209 LPALEFFECTIV alEffectiv{nullptr};
210 LPALEFFECTF alEffectf{nullptr};
211 LPALEFFECTFV alEffectfv{nullptr};
212 LPALGETEFFECTI alGetEffecti{nullptr};
213 LPALGETEFFECTIV alGetEffectiv{nullptr};
214 LPALGETEFFECTF alGetEffectf{nullptr};
215 LPALGETEFFECTFV alGetEffectfv{nullptr};
217 LPALGENFILTERS alGenFilters{nullptr};
218 LPALDELETEFILTERS alDeleteFilters{nullptr};
219 LPALISFILTER alIsFilter{nullptr};
220 LPALFILTERI alFilteri{nullptr};
221 LPALFILTERIV alFilteriv{nullptr};
222 LPALFILTERF alFilterf{nullptr};
223 LPALFILTERFV alFilterfv{nullptr};
224 LPALGETFILTERI alGetFilteri{nullptr};
225 LPALGETFILTERIV alGetFilteriv{nullptr};
226 LPALGETFILTERF alGetFilterf{nullptr};
227 LPALGETFILTERFV alGetFilterfv{nullptr};
229 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{nullptr};
230 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{nullptr};
231 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{nullptr};
232 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{nullptr};
233 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{nullptr};
234 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{nullptr};
235 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{nullptr};
236 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{nullptr};
237 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{nullptr};
238 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{nullptr};
239 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{nullptr};
241 FutureBufferListT::const_iterator findFutureBufferName(StringView name, size_t name_hash) const;
242 BufferListT::const_iterator findBufferName(StringView name, size_t name_hash) const;
244 ALuint getSourceId(ALuint maxprio);
245 void insertSourceId(ALuint id) { mSourceIds.push_back(id); }
247 void addPendingSource(SourceImpl *source, SharedFuture<Buffer> future);
248 void removePendingSource(SourceImpl *source);
249 bool isPendingSource(const SourceImpl *source) const;
250 void addFadingSource(SourceImpl *source, std::chrono::nanoseconds duration, ALfloat gain);
251 void removeFadingSource(SourceImpl *source);
252 void addPlayingSource(SourceImpl *source, ALuint id);
253 void addPlayingSource(SourceImpl *source);
254 void removePlayingSource(SourceImpl *source);
256 void addStream(SourceImpl *source);
257 void removeStream(SourceImpl *source);
258 void removeStreamNoLock(SourceImpl *source);
260 void freeSource(SourceImpl *source) { mFreeSources.push_back(source); }
261 void freeSourceGroup(SourceGroupImpl *group);
262 void freeEffectSlot(AuxiliaryEffectSlotImpl *slot);
263 void freeEffect(EffectImpl *effect);
265 Batcher getBatcher()
267 if(mIsBatching)
268 return Batcher(nullptr);
269 alcSuspendContext(mContext.get());
270 return Batcher(mContext.get());
273 std::unique_lock<std::mutex> getSourceStreamLock()
274 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
276 template<typename R, typename... Args>
277 void send(R MessageHandler::* func, Args&&... args)
278 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
280 Device getDevice() { return Device(&mDevice); }
282 void destroy();
284 void startBatch();
285 void endBatch();
287 Listener getListener() { return Listener(&mListener); }
289 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler>&& handler);
290 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
292 void setAsyncWakeInterval(std::chrono::milliseconds interval);
293 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
295 SharedPtr<Decoder> createDecoder(StringView name);
297 bool isSupported(ChannelConfig channels, SampleType type) const;
299 ArrayView<String> getAvailableResamplers();
300 ALsizei getDefaultResamplerIndex() const;
302 Buffer getBuffer(StringView name);
303 SharedFuture<Buffer> getBufferAsync(StringView name);
304 void precacheBuffersAsync(ArrayView<StringView> names);
305 Buffer createBufferFrom(StringView name, SharedPtr<Decoder>&& decoder);
306 SharedFuture<Buffer> createBufferAsyncFrom(StringView name, SharedPtr<Decoder>&& decoder);
307 Buffer findBuffer(StringView name);
308 SharedFuture<Buffer> findBufferAsync(StringView name);
309 void removeBuffer(StringView name);
310 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
312 Source createSource();
314 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
316 Effect createEffect();
318 SourceGroup createSourceGroup();
320 void setDopplerFactor(ALfloat factor);
322 void setSpeedOfSound(ALfloat speed);
324 void setDistanceModel(DistanceModel model);
326 void update();
330 inline void CheckContext(const ContextImpl &ctx)
332 auto count = ContextImpl::sContextSetCount.load(std::memory_order_acquire);
333 if(UNLIKELY(count != ctx.mContextSetCounter))
335 if(UNLIKELY(&ctx != ContextImpl::GetCurrent()))
336 throw std::runtime_error("Called context is not current");
337 ctx.mContextSetCounter = count;
341 inline void CheckContexts(const ContextImpl &ctx0, const ContextImpl &ctx1)
343 if(UNLIKELY(&ctx0 != &ctx1))
344 throw std::runtime_error("Mismatched object contexts");
348 } // namespace alure
350 #endif /* CONTEXT_H */