Move the decoder when creating a PendingFuture
[alure.git] / src / context.h
blob2cce34777f623637690971585b8e521c1b9b5c05
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 private:
113 ListenerImpl mListener;
114 ALCcontext *mContext{nullptr};
115 Vector<ALuint> mSourceIds;
117 struct PendingBuffer { BufferImpl *mBuffer; SharedFuture<Buffer> mFuture; };
118 struct PendingSource { SourceImpl *mSource; SharedFuture<Buffer> mFuture; };
120 DeviceImpl *const mDevice{nullptr};
121 Vector<PendingBuffer> mFutureBuffers;
122 Vector<UniquePtr<BufferImpl>> mBuffers;
123 Vector<UniquePtr<SourceGroupImpl>> mSourceGroups;
124 Vector<UniquePtr<AuxiliaryEffectSlotImpl>> mEffectSlots;
125 Vector<UniquePtr<EffectImpl>> mEffects;
126 std::deque<SourceImpl> mAllSources;
127 Vector<SourceImpl*> mFreeSources;
129 Vector<PendingSource> mPendingSources;
130 Vector<SourceImpl*> mFadingSources;
131 Vector<SourceBufferUpdateEntry> mPlaySources;
132 Vector<SourceStreamUpdateEntry> mStreamSources;
134 Vector<SourceImpl*> mStreamingSources;
135 std::mutex mSourceStreamMutex;
137 std::atomic<std::chrono::milliseconds> mWakeInterval{std::chrono::milliseconds::zero()};
138 std::mutex mWakeMutex;
139 std::condition_variable mWakeThread;
141 SharedPtr<MessageHandler> mMessage;
143 struct PendingPromise {
144 BufferImpl *mBuffer;
145 SharedPtr<Decoder> mDecoder;
146 ALenum mFormat;
147 ALuint mFrames;
148 Promise<Buffer> mPromise;
150 std::atomic<PendingPromise*> mNext;
152 std::atomic<PendingPromise*> mPendingCurrent{nullptr};
153 PendingPromise *mPendingTail{nullptr};
154 PendingPromise *mPendingHead{nullptr};
156 std::atomic<bool> mQuitThread{false};
157 std::thread mThread;
158 void backgroundProc();
160 size_t mRefs{0};
162 Vector<String> mResamplers;
164 Bitfield<static_cast<size_t>(AL::EXTENSION_MAX)> mHasExt;
166 std::once_flag mSetExts;
167 void setupExts();
169 DecoderOrExceptT findDecoder(StringView name);
170 BufferOrExceptT doCreateBuffer(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder);
171 BufferOrExceptT doCreateBufferAsync(StringView name, Vector<UniquePtr<BufferImpl>>::iterator iter, SharedPtr<Decoder> decoder, Promise<Buffer> promise);
173 bool mIsConnected : 1;
174 bool mIsBatching : 1;
176 public:
177 ContextImpl(ALCcontext *context, DeviceImpl *device);
178 ~ContextImpl();
180 ALCcontext *getALCcontext() const { return mContext; }
181 long addRef() { return ++mRefs; }
182 long decRef() { return --mRefs; }
184 bool hasExtension(AL ext) const { return mHasExt[static_cast<size_t>(ext)]; }
186 LPALGETSTRINGISOFT alGetStringiSOFT{nullptr};
187 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT{nullptr};
188 LPALGETSOURCEDVSOFT alGetSourcedvSOFT{nullptr};
190 LPALGENEFFECTS alGenEffects{nullptr};
191 LPALDELETEEFFECTS alDeleteEffects{nullptr};
192 LPALISEFFECT alIsEffect{nullptr};
193 LPALEFFECTI alEffecti{nullptr};
194 LPALEFFECTIV alEffectiv{nullptr};
195 LPALEFFECTF alEffectf{nullptr};
196 LPALEFFECTFV alEffectfv{nullptr};
197 LPALGETEFFECTI alGetEffecti{nullptr};
198 LPALGETEFFECTIV alGetEffectiv{nullptr};
199 LPALGETEFFECTF alGetEffectf{nullptr};
200 LPALGETEFFECTFV alGetEffectfv{nullptr};
202 LPALGENFILTERS alGenFilters{nullptr};
203 LPALDELETEFILTERS alDeleteFilters{nullptr};
204 LPALISFILTER alIsFilter{nullptr};
205 LPALFILTERI alFilteri{nullptr};
206 LPALFILTERIV alFilteriv{nullptr};
207 LPALFILTERF alFilterf{nullptr};
208 LPALFILTERFV alFilterfv{nullptr};
209 LPALGETFILTERI alGetFilteri{nullptr};
210 LPALGETFILTERIV alGetFilteriv{nullptr};
211 LPALGETFILTERF alGetFilterf{nullptr};
212 LPALGETFILTERFV alGetFilterfv{nullptr};
214 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{nullptr};
215 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{nullptr};
216 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{nullptr};
217 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{nullptr};
218 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{nullptr};
219 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{nullptr};
220 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{nullptr};
221 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{nullptr};
222 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{nullptr};
223 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{nullptr};
224 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{nullptr};
226 ALuint getSourceId(ALuint maxprio);
227 void insertSourceId(ALuint id) { mSourceIds.push_back(id); }
229 void addPendingSource(SourceImpl *source, SharedFuture<Buffer> future);
230 void removePendingSource(SourceImpl *source);
231 bool isPendingSource(const SourceImpl *source) const;
232 void addFadingSource(SourceImpl *source);
233 void removeFadingSource(SourceImpl *source);
234 void addPlayingSource(SourceImpl *source, ALuint id);
235 void addPlayingSource(SourceImpl *source);
236 void removePlayingSource(SourceImpl *source);
238 void addStream(SourceImpl *source);
239 void removeStream(SourceImpl *source);
240 void removeStreamNoLock(SourceImpl *source);
242 void freeSource(SourceImpl *source) { mFreeSources.push_back(source); }
243 void freeSourceGroup(SourceGroupImpl *group);
244 void freeEffectSlot(AuxiliaryEffectSlotImpl *slot);
245 void freeEffect(EffectImpl *effect);
247 Batcher getBatcher()
249 if(mIsBatching)
250 return Batcher(nullptr);
251 alcSuspendContext(mContext);
252 return Batcher(mContext);
255 std::unique_lock<std::mutex> getSourceStreamLock()
256 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
258 template<typename R, typename... Args>
259 void send(R MessageHandler::* func, Args&&... args)
260 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
262 Device getDevice() { return Device(mDevice); }
264 void destroy();
266 void startBatch();
267 void endBatch();
269 Listener getListener() { return Listener(&mListener); }
271 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler>&& handler);
272 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
274 void setAsyncWakeInterval(std::chrono::milliseconds interval);
275 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
277 SharedPtr<Decoder> createDecoder(StringView name);
279 bool isSupported(ChannelConfig channels, SampleType type) const;
281 ArrayView<String> getAvailableResamplers();
282 ALsizei getDefaultResamplerIndex() const;
284 Buffer getBuffer(StringView name);
285 SharedFuture<Buffer> getBufferAsync(StringView name);
286 void precacheBuffersAsync(ArrayView<StringView> names);
287 Buffer createBufferFrom(StringView name, SharedPtr<Decoder>&& decoder);
288 SharedFuture<Buffer> createBufferAsyncFrom(StringView name, SharedPtr<Decoder>&& decoder);
289 Buffer findBuffer(StringView name);
290 SharedFuture<Buffer> findBufferAsync(StringView name);
291 void removeBuffer(StringView name);
292 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
294 Source createSource();
296 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
298 Effect createEffect();
300 SourceGroup createSourceGroup();
302 void setDopplerFactor(ALfloat factor);
304 void setSpeedOfSound(ALfloat speed);
306 void setDistanceModel(DistanceModel model);
308 void update();
312 inline void CheckContext(const ContextImpl *ctx)
314 auto count = ContextImpl::sContextSetCount.load(std::memory_order_acquire);
315 if(UNLIKELY(count != ctx->mContextSetCounter))
317 if(UNLIKELY(ctx != ContextImpl::GetCurrent()))
318 throw std::runtime_error("Called context is not current");
319 ctx->mContextSetCounter = count;
323 inline void CheckContexts(const ContextImpl *ctx0, const ContextImpl *ctx1)
325 if(UNLIKELY(ctx0 != ctx1))
326 throw std::runtime_error("Mismatched object contexts");
330 } // namespace alure
332 #endif /* CONTEXT_H */