Return the exception from doCreateBuffer functions instead of throwing
[alure.git] / src / context.h
blob01aec597fc74d9a8d5917e04608e0c24c54f6cd6
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 // TODO: Can use <variant> with a C++17-compliant compiler.
15 #include "mpark/variant.hpp"
17 #include "alc.h"
18 #include "alext.h"
20 #include "refcount.h"
21 #include "ringbuf.h"
22 #include "device.h"
23 #include "source.h"
25 #define F_PI (3.14159265358979323846f)
27 namespace alure {
29 // TODO: Can use std::variant stuff with a C++17-compliant compiler.
30 template<typename T>
31 using AddPointerT = typename std::add_pointer<T>::type;
32 template<typename ...Ts>
33 using Variant = mpark::variant<Ts...>;
34 template<typename T, typename ...Ts>
35 inline constexpr T& Get(Variant<Ts...> &v) { return mpark::get<T>(v); }
36 template<size_t I, typename ...Ts>
37 inline constexpr mpark::variant_alternative_t<I,Variant<Ts...>>& Get(Variant<Ts...> &v) { return mpark::get<I>(v); }
38 template<typename T, typename ...Ts>
39 inline constexpr AddPointerT<T> GetIf(Variant<Ts...> *v) noexcept { return mpark::get_if<T>(v); }
40 template<size_t I, typename ...Ts>
41 inline constexpr AddPointerT<mpark::variant_alternative_t<I,Variant<Ts...>>> GetIf(Variant<Ts...> *v) noexcept { return mpark::get_if<I>(v); }
43 class ALDevice;
44 class ALBuffer;
45 class ALSourceGroup;
47 enum ALExtension {
48 EXT_EFX,
50 EXT_FLOAT32,
51 EXT_MCFORMATS,
52 EXT_BFORMAT,
54 EXT_MULAW,
55 EXT_MULAW_MCFORMATS,
56 EXT_MULAW_BFORMAT,
58 SOFT_loop_points,
59 SOFT_source_latency,
60 SOFT_source_resampler,
61 SOFT_source_spatialize,
63 EXT_disconnect,
65 EXT_SOURCE_RADIUS,
66 EXT_STEREO_ANGLES,
68 AL_EXTENSION_MAX
71 // Batches OpenAL updates while the object is alive, if batching isn't already
72 // in progress.
73 class Batcher {
74 ALCcontext *mContext;
76 public:
77 Batcher(ALCcontext *context) : mContext(context) { }
78 Batcher(Batcher&& rhs) : mContext(rhs.mContext) { rhs.mContext = nullptr; }
79 Batcher(const Batcher&) = delete;
80 ~Batcher()
82 if(mContext)
83 alcProcessContext(mContext);
86 Batcher& operator=(Batcher&&) = delete;
87 Batcher& operator=(const Batcher&) = delete;
91 class ALListener {
92 ALContext *const mContext;
94 public:
95 ALListener(ALContext *ctx) : mContext(ctx) { }
97 void setGain(ALfloat gain);
99 void set3DParameters(const Vector3 &position, const Vector3 &velocity, std::pair<Vector3,Vector3> orientation);
101 void setPosition(ALfloat x, ALfloat y, ALfloat z);
102 void setPosition(const ALfloat *pos);
104 void setVelocity(ALfloat x, ALfloat y, ALfloat z);
105 void setVelocity(const ALfloat *vel);
107 void setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2);
108 void setOrientation(const ALfloat *at, const ALfloat *up);
109 void setOrientation(const ALfloat *ori);
111 void setMetersPerUnit(ALfloat m_u);
115 using BufferOrExceptT = Variant<Buffer,std::runtime_error>;
117 class ALContext {
118 static ALContext *sCurrentCtx;
119 static thread_local ALContext *sThreadCurrentCtx;
121 public:
122 static void MakeCurrent(ALContext *context);
123 static ALContext *GetCurrent() { return sThreadCurrentCtx ? sThreadCurrentCtx : sCurrentCtx; }
125 static void MakeThreadCurrent(ALContext *context);
126 static ALContext *GetThreadCurrent() { return sThreadCurrentCtx; }
128 private:
129 ALListener mListener;
130 ALCcontext *mContext;
131 std::stack<ALuint> mSourceIds;
133 ALDevice *const mDevice;
134 std::deque<ALSource> mAllSources;
135 std::queue<ALSource*> mFreeSources;
136 Vector<ALSource*> mUsedSources;
138 Vector<UniquePtr<ALBuffer>> mBuffers;
140 Vector<UniquePtr<ALSourceGroup>> mSourceGroups;
142 RefCount mRefs;
144 Vector<String> mResamplers;
146 SharedPtr<MessageHandler> mMessage;
148 bool mHasExt[AL_EXTENSION_MAX];
150 struct PendingBuffer {
151 String mName;
152 ALBuffer *mBuffer;
153 SharedPtr<Decoder> mDecoder;
154 ALenum mFormat;
155 ALuint mFrames;
157 ~PendingBuffer() { }
159 RingBuffer mPendingBuffers;
161 Vector<ALSource*> mStreamingSources;
162 std::mutex mSourceStreamMutex;
164 std::atomic<std::chrono::milliseconds> mWakeInterval;
165 std::mutex mWakeMutex;
166 std::condition_variable mWakeThread;
168 std::mutex mContextMutex;
170 std::atomic<bool> mQuitThread;
171 std::thread mThread;
172 void backgroundProc();
174 std::once_flag mSetExts;
175 void setupExts();
177 BufferOrExceptT doCreateBuffer(const String &name, Vector<UniquePtr<ALBuffer>>::iterator iter, SharedPtr<Decoder> decoder);
178 BufferOrExceptT doCreateBufferAsync(const String &name, Vector<UniquePtr<ALBuffer>>::iterator iter, SharedPtr<Decoder> decoder);
180 bool mIsConnected : 1;
181 bool mIsBatching : 1;
183 public:
184 ALContext(ALCcontext *context, ALDevice *device);
185 ~ALContext();
187 ALCcontext *getContext() const { return mContext; }
188 long addRef() { return ++mRefs; }
189 long decRef() { return --mRefs; }
191 bool hasExtension(ALExtension ext) const { return mHasExt[ext]; }
193 LPALGETSTRINGISOFT alGetStringiSOFT;
194 LPALGETSOURCEI64VSOFT alGetSourcei64vSOFT;
195 LPALGETSOURCEDVSOFT alGetSourcedvSOFT;
197 LPALGENEFFECTS alGenEffects;
198 LPALDELETEEFFECTS alDeleteEffects;
199 LPALISEFFECT alIsEffect;
200 LPALEFFECTI alEffecti;
201 LPALEFFECTIV alEffectiv;
202 LPALEFFECTF alEffectf;
203 LPALEFFECTFV alEffectfv;
204 LPALGETEFFECTI alGetEffecti;
205 LPALGETEFFECTIV alGetEffectiv;
206 LPALGETEFFECTF alGetEffectf;
207 LPALGETEFFECTFV alGetEffectfv;
209 LPALGENFILTERS alGenFilters;
210 LPALDELETEFILTERS alDeleteFilters;
211 LPALISFILTER alIsFilter;
212 LPALFILTERI alFilteri;
213 LPALFILTERIV alFilteriv;
214 LPALFILTERF alFilterf;
215 LPALFILTERFV alFilterfv;
216 LPALGETFILTERI alGetFilteri;
217 LPALGETFILTERIV alGetFilteriv;
218 LPALGETFILTERF alGetFilterf;
219 LPALGETFILTERFV alGetFilterfv;
221 LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
222 LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
223 LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
224 LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
225 LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
226 LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
227 LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
228 LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
229 LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
230 LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
231 LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
233 ALuint getSourceId(ALuint maxprio);
234 void insertSourceId(ALuint id) { mSourceIds.push(id); }
236 void addStream(ALSource *source);
237 void removeStream(ALSource *source);
238 void removeStreamNoLock(ALSource *source);
240 void freeSource(ALSource *source);
241 void freeSourceGroup(ALSourceGroup *group);
243 Batcher getBatcher()
245 if(mIsBatching)
246 return Batcher(nullptr);
247 alcSuspendContext(mContext);
248 return Batcher(mContext);
251 std::unique_lock<std::mutex> getSourceStreamLock()
252 { return std::unique_lock<std::mutex>(mSourceStreamMutex); }
254 template<typename R, typename... Args>
255 void send(R MessageHandler::* func, Args&&... args)
256 { if(mMessage.get()) (mMessage.get()->*func)(std::forward<Args>(args)...); }
258 Device getDevice() { return Device(mDevice); }
260 void destroy();
262 void startBatch();
263 void endBatch();
265 Listener getListener() { return Listener(&mListener); }
267 SharedPtr<MessageHandler> setMessageHandler(SharedPtr<MessageHandler> handler);
268 SharedPtr<MessageHandler> getMessageHandler() const { return mMessage; }
270 void setAsyncWakeInterval(std::chrono::milliseconds msec);
271 std::chrono::milliseconds getAsyncWakeInterval() const { return mWakeInterval.load(); }
273 SharedPtr<Decoder> createDecoder(const String &name);
275 bool isSupported(ChannelConfig channels, SampleType type) const;
277 const Vector<String> &getAvailableResamplers();
278 ALsizei getDefaultResamplerIndex() const;
280 Buffer getBuffer(const String &name);
281 Buffer getBufferAsync(const String &name);
282 Buffer createBufferFrom(const String &name, SharedPtr<Decoder> decoder);
283 Buffer createBufferAsyncFrom(const String &name, SharedPtr<Decoder> decoder);
284 void removeBuffer(const String &name);
285 void removeBuffer(Buffer buffer) { removeBuffer(buffer.getName()); }
287 Source createSource();
289 AuxiliaryEffectSlot createAuxiliaryEffectSlot();
291 Effect createEffect();
293 SourceGroup createSourceGroup(String name);
294 SourceGroup getSourceGroup(const String &name);
296 void setDopplerFactor(ALfloat factor);
298 void setSpeedOfSound(ALfloat speed);
300 void setDistanceModel(DistanceModel model);
302 void update();
306 inline void CheckContext(const ALContext *ctx)
308 if(EXPECT(ctx != ALContext::GetCurrent(), false))
309 throw std::runtime_error("Called context is not current");
312 } // namespace alure
314 #endif /* CONTEXT_H */