Remove constexpr from Vector3::getLength and getDistance
[alure.git] / src / context.cpp
blob7006b538afc983b78182c2d2144bcd142d90ffce
2 #include "config.h"
4 #include "context.h"
6 #include <stdexcept>
7 #include <algorithm>
8 #include <functional>
9 #include <memory>
10 #include <iostream>
11 #include <sstream>
12 #include <fstream>
13 #include <cstring>
14 #include <map>
15 #include <new>
17 #include "alc.h"
19 #ifdef HAVE_VORBISFILE
20 #include "decoders/vorbisfile.hpp"
21 #endif
22 #ifdef HAVE_LIBFLAC
23 #include "decoders/flac.hpp"
24 #endif
25 #ifdef HAVE_OPUSFILE
26 #include "decoders/opusfile.hpp"
27 #endif
28 #ifdef HAVE_LIBSNDFILE
29 #include "decoders/sndfile.hpp"
30 #endif
31 #ifdef HAVE_MPG123
32 #include "decoders/mpg123.hpp"
33 #endif
34 #include "decoders/wave.hpp"
36 #include "devicemanager.h"
37 #include "device.h"
38 #include "buffer.h"
39 #include "source.h"
40 #include "auxeffectslot.h"
41 #include "effect.h"
42 #include <sourcegroup.h>
44 namespace alure
47 static const std::pair<String,UniquePtr<DecoderFactory>> sDefaultDecoders[] = {
48 { "_alure_int_wave", MakeUnique<WaveDecoderFactory>() },
50 #ifdef HAVE_VORBISFILE
51 { "_alure_int_vorbis", MakeUnique<VorbisFileDecoderFactory>() },
52 #endif
53 #ifdef HAVE_LIBFLAC
54 { "_alure_int_flac", MakeUnique<FlacDecoderFactory>() },
55 #endif
56 #ifdef HAVE_OPUSFILE
57 { "_alure_int_opus", MakeUnique<OpusFileDecoderFactory>() },
58 #endif
59 #ifdef HAVE_LIBSNDFILE
60 { "_alure_int_sndfile", MakeUnique<SndFileDecoderFactory>() },
61 #endif
62 #ifdef HAVE_MPG123
63 { "_alure_int_mpg123", MakeUnique<Mpg123DecoderFactory>() },
64 #endif
67 static std::map<String,UniquePtr<DecoderFactory>> sDecoders;
70 template<typename T>
71 static SharedPtr<Decoder> GetDecoder(const String &name, UniquePtr<std::istream> &file, T start, T end)
73 while(start != end)
75 DecoderFactory *factory = start->second.get();
76 auto decoder = factory->createDecoder(file);
77 if(decoder) return decoder;
79 if(!file || !(file->clear(),file->seekg(0)))
80 throw std::runtime_error("Failed to rewind "+name+" for the next decoder factory");
82 ++start;
85 return nullptr;
88 static SharedPtr<Decoder> GetDecoder(const String &name, UniquePtr<std::istream> file)
90 auto decoder = GetDecoder(name, file, sDecoders.begin(), sDecoders.end());
91 if(!decoder) decoder = GetDecoder(name, file, std::begin(sDefaultDecoders), std::end(sDefaultDecoders));
92 if(!decoder) throw std::runtime_error("No decoder for "+name);
93 return decoder;
96 void RegisterDecoder(const String &name, UniquePtr<DecoderFactory> factory)
98 while(sDecoders.find(name) != sDecoders.end())
99 throw std::runtime_error("Decoder factory \""+name+"\" already registered");
100 sDecoders.insert(std::make_pair(name, std::move(factory)));
103 UniquePtr<DecoderFactory> UnregisterDecoder(const String &name)
105 auto iter = sDecoders.find(name);
106 if(iter != sDecoders.end())
108 UniquePtr<DecoderFactory> factory = std::move(iter->second);
109 sDecoders.erase(iter);
110 return factory;
112 return nullptr;
116 class DefaultFileIOFactory : public FileIOFactory {
117 UniquePtr<std::istream> openFile(const String &name) override final
119 auto file = MakeUnique<std::ifstream>(name.c_str(), std::ios::binary);
120 if(!file->is_open()) file = nullptr;
121 return std::move(file);
124 static DefaultFileIOFactory sDefaultFileFactory;
126 static UniquePtr<FileIOFactory> sFileFactory;
127 UniquePtr<FileIOFactory> FileIOFactory::set(UniquePtr<FileIOFactory> factory)
129 std::swap(sFileFactory, factory);
130 return factory;
133 FileIOFactory &FileIOFactory::get()
135 FileIOFactory *factory = sFileFactory.get();
136 if(factory) return *factory;
137 return sDefaultFileFactory;
141 // Default message handler methods are no-ops.
142 MessageHandler::~MessageHandler()
146 void MessageHandler::deviceDisconnected(Device*)
150 void MessageHandler::sourceStopped(Source*, bool)
154 void MessageHandler::bufferLoading(const String&, ChannelConfig, SampleType, ALuint, const Vector<ALbyte>&)
158 String MessageHandler::resourceNotFound(const String&)
160 return String();
164 template<typename T>
165 static inline void LoadALFunc(T **func, const char *name)
166 { *func = reinterpret_cast<T*>(alGetProcAddress(name)); }
168 static void LoadNothing(ALContext*) { }
170 static void LoadEFX(ALContext *ctx)
172 LoadALFunc(&ctx->alGenEffects, "alGenEffects");
173 LoadALFunc(&ctx->alDeleteEffects, "alDeleteEffects");
174 LoadALFunc(&ctx->alIsEffect, "alIsEffect");
175 LoadALFunc(&ctx->alEffecti, "alEffecti");
176 LoadALFunc(&ctx->alEffectiv, "alEffectiv");
177 LoadALFunc(&ctx->alEffectf, "alEffectf");
178 LoadALFunc(&ctx->alEffectfv, "alEffectfv");
179 LoadALFunc(&ctx->alGetEffecti, "alGetEffecti");
180 LoadALFunc(&ctx->alGetEffectiv, "alGetEffectiv");
181 LoadALFunc(&ctx->alGetEffectf, "alGetEffectf");
182 LoadALFunc(&ctx->alGetEffectfv, "alGetEffectfv");
184 LoadALFunc(&ctx->alGenFilters, "alGenFilters");
185 LoadALFunc(&ctx->alDeleteFilters, "alDeleteFilters");
186 LoadALFunc(&ctx->alIsFilter, "alIsFilter");
187 LoadALFunc(&ctx->alFilteri, "alFilteri");
188 LoadALFunc(&ctx->alFilteriv, "alFilteriv");
189 LoadALFunc(&ctx->alFilterf, "alFilterf");
190 LoadALFunc(&ctx->alFilterfv, "alFilterfv");
191 LoadALFunc(&ctx->alGetFilteri, "alGetFilteri");
192 LoadALFunc(&ctx->alGetFilteriv, "alGetFilteriv");
193 LoadALFunc(&ctx->alGetFilterf, "alGetFilterf");
194 LoadALFunc(&ctx->alGetFilterfv, "alGetFilterfv");
196 LoadALFunc(&ctx->alGenAuxiliaryEffectSlots, "alGenAuxiliaryEffectSlots");
197 LoadALFunc(&ctx->alDeleteAuxiliaryEffectSlots, "alDeleteAuxiliaryEffectSlots");
198 LoadALFunc(&ctx->alIsAuxiliaryEffectSlot, "alIsAuxiliaryEffectSlot");
199 LoadALFunc(&ctx->alAuxiliaryEffectSloti, "alAuxiliaryEffectSloti");
200 LoadALFunc(&ctx->alAuxiliaryEffectSlotiv, "alAuxiliaryEffectSlotiv");
201 LoadALFunc(&ctx->alAuxiliaryEffectSlotf, "alAuxiliaryEffectSlotf");
202 LoadALFunc(&ctx->alAuxiliaryEffectSlotfv, "alAuxiliaryEffectSlotfv");
203 LoadALFunc(&ctx->alGetAuxiliaryEffectSloti, "alGetAuxiliaryEffectSloti");
204 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotiv, "alGetAuxiliaryEffectSlotiv");
205 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotf, "alGetAuxiliaryEffectSlotf");
206 LoadALFunc(&ctx->alGetAuxiliaryEffectSlotfv, "alGetAuxiliaryEffectSlotfv");
209 static void LoadSourceLatency(ALContext *ctx)
211 LoadALFunc(&ctx->alGetSourcei64vSOFT, "alGetSourcei64vSOFT");
214 static const struct {
215 enum ALExtension extension;
216 const char name[32];
217 void (&loader)(ALContext*);
218 } ALExtensionList[] = {
219 { EXT_EFX, "ALC_EXT_EFX", LoadEFX },
221 { EXT_FLOAT32, "AL_EXT_FLOAT32", LoadNothing },
222 { EXT_MCFORMATS, "AL_EXT_MCFORMATS", LoadNothing },
223 { EXT_BFORMAT, "AL_EXT_BFORMAT", LoadNothing },
225 { EXT_MULAW, "AL_EXT_MULAW", LoadNothing },
226 { EXT_MULAW_MCFORMATS, "AL_EXT_MULAW_MCFORMATS", LoadNothing },
227 { EXT_MULAW_BFORMAT, "AL_EXT_MULAW_BFORMAT", LoadNothing },
229 { SOFT_loop_points, "AL_SOFT_loop_points", LoadNothing },
230 { SOFT_source_latency, "AL_SOFT_source_latency", LoadSourceLatency },
232 { EXT_disconnect, "ALC_EXT_disconnect", LoadNothing },
234 { EXT_SOURCE_RADIUS, "AL_EXT_SOURCE_RADIUS", LoadNothing },
235 { EXT_STEREO_ANGLES, "AL_EXT_STEREO_ANGLES", LoadNothing },
239 ALContext *ALContext::sCurrentCtx = nullptr;
240 thread_local ALContext *ALContext::sThreadCurrentCtx = nullptr;
242 void ALContext::MakeCurrent(ALContext *context)
244 std::unique_lock<std::mutex> lock1, lock2;
245 if(sCurrentCtx)
246 lock1 = std::unique_lock<std::mutex>(sCurrentCtx->mContextMutex);
247 if(context && context != sCurrentCtx)
248 lock2 = std::unique_lock<std::mutex>(context->mContextMutex);
250 if(alcMakeContextCurrent(context ? context->getContext() : 0) == ALC_FALSE)
251 throw std::runtime_error("Call to alcMakeContextCurrent failed");
252 if(context)
254 context->addRef();
255 std::call_once(context->mSetExts, std::mem_fn(&ALContext::setupExts), context);
257 std::swap(sCurrentCtx, context);
258 if(context) context->decRef();
260 if(sThreadCurrentCtx)
261 sThreadCurrentCtx->decRef();
262 sThreadCurrentCtx = 0;
264 if(sCurrentCtx && sCurrentCtx != context)
266 lock2.unlock();
267 sCurrentCtx->mWakeThread.notify_all();
271 void ALContext::MakeThreadCurrent(ALContext *context)
273 if(!ALDeviceManager::SetThreadContext)
274 throw std::runtime_error("Thread-local contexts unsupported");
275 if(ALDeviceManager::SetThreadContext(context ? context->getContext() : nullptr) == ALC_FALSE)
276 throw std::runtime_error("Call to alcSetThreadContext failed");
277 if(context)
279 context->addRef();
280 std::call_once(context->mSetExts, std::mem_fn(&ALContext::setupExts), context);
282 if(sThreadCurrentCtx)
283 sThreadCurrentCtx->decRef();
284 sThreadCurrentCtx = context;
287 void ALContext::setupExts()
289 ALCdevice *device = mDevice->getDevice();
290 std::fill(std::begin(mHasExt), std::end(mHasExt), false);
291 for(const auto &entry : ALExtensionList)
293 mHasExt[entry.extension] = (strncmp(entry.name, "ALC", 3) == 0) ?
294 alcIsExtensionPresent(device, entry.name) :
295 alIsExtensionPresent(entry.name);
296 if(mHasExt[entry.extension]) entry.loader(this);
301 void ALContext::backgroundProc()
303 if(ALDeviceManager::SetThreadContext && mDevice->hasExtension(EXT_thread_local_context))
304 ALDeviceManager::SetThreadContext(getContext());
306 std::chrono::steady_clock::time_point basetime = std::chrono::steady_clock::now();
307 std::chrono::milliseconds waketime(0);
308 std::unique_lock<std::mutex> ctxlock(mContextMutex);
309 while(!mQuitThread.load(std::memory_order_acquire))
312 std::lock_guard<std::mutex> srclock(mSourceStreamMutex);
313 auto source = mStreamingSources.begin();
314 while(source != mStreamingSources.end())
316 if(!(*source)->updateAsync())
317 source = mStreamingSources.erase(source);
318 else
319 ++source;
323 // Only do one pending buffer at a time. In case there's several large
324 // buffers to load, we still need to process streaming sources so they
325 // don't underrun.
326 RingBuffer::Data ringdata = mPendingBuffers.get_read_vector()[0];
327 if(ringdata.len > 0)
329 PendingBuffer *pb = reinterpret_cast<PendingBuffer*>(ringdata.buf);
330 pb->mBuffer->load(pb->mFrames, pb->mFormat, pb->mDecoder, pb->mName, this);
331 pb->~PendingBuffer();
332 mPendingBuffers.read_advance(1);
333 continue;
336 std::unique_lock<std::mutex> wakelock(mWakeMutex);
337 if(!mQuitThread.load(std::memory_order_acquire) && mPendingBuffers.read_space() == 0)
339 ctxlock.unlock();
341 ALuint interval = mWakeInterval.load();
342 if(!interval)
343 mWakeThread.wait(wakelock);
344 else
346 auto now = std::chrono::steady_clock::now() - basetime;
347 auto duration = std::chrono::milliseconds(interval);
348 while((waketime - now).count() <= 0) waketime += duration;
349 mWakeThread.wait_until(wakelock, waketime + basetime);
351 wakelock.unlock();
353 ctxlock.lock();
354 while(!mQuitThread.load(std::memory_order_acquire) &&
355 alcGetCurrentContext() != getContext())
356 mWakeThread.wait(ctxlock);
359 ctxlock.unlock();
361 if(ALDeviceManager::SetThreadContext)
362 ALDeviceManager::SetThreadContext(nullptr);
366 ALContext::ALContext(ALCcontext *context, ALDevice *device)
367 : mContext(context), mDevice(device), mRefs(0),
368 mHasExt{false}, mPendingBuffers(16, sizeof(PendingBuffer)),
369 mWakeInterval(0), mQuitThread(false), mIsConnected(true), mIsBatching(false),
370 alGetSourcei64vSOFT(0),
371 alGenEffects(0), alDeleteEffects(0), alIsEffect(0),
372 alEffecti(0), alEffectiv(0), alEffectf(0), alEffectfv(0),
373 alGetEffecti(0), alGetEffectiv(0), alGetEffectf(0), alGetEffectfv(0),
374 alGenFilters(0), alDeleteFilters(0), alIsFilter(0),
375 alFilteri(0), alFilteriv(0), alFilterf(0), alFilterfv(0),
376 alGetFilteri(0), alGetFilteriv(0), alGetFilterf(0), alGetFilterfv(0),
377 alGenAuxiliaryEffectSlots(0), alDeleteAuxiliaryEffectSlots(0), alIsAuxiliaryEffectSlot(0),
378 alAuxiliaryEffectSloti(0), alAuxiliaryEffectSlotiv(0), alAuxiliaryEffectSlotf(0), alAuxiliaryEffectSlotfv(0),
379 alGetAuxiliaryEffectSloti(0), alGetAuxiliaryEffectSlotiv(0), alGetAuxiliaryEffectSlotf(0), alGetAuxiliaryEffectSlotfv(0)
383 ALContext::~ALContext()
385 auto ringdata = mPendingBuffers.get_read_vector();
386 if(ringdata[0].len > 0)
388 PendingBuffer *pb = reinterpret_cast<PendingBuffer*>(ringdata[0].buf);
389 for(size_t i = 0;i < ringdata[0].len;i++)
390 pb[i].~PendingBuffer();
391 pb = reinterpret_cast<PendingBuffer*>(ringdata[1].buf);
392 for(size_t i = 0;i < ringdata[1].len;i++)
393 pb[i].~PendingBuffer();
395 mPendingBuffers.read_advance(ringdata[0].len + ringdata[1].len);
400 Device *ALContext::getDevice()
402 return mDevice;
405 void ALContext::destroy()
407 if(mRefs.load() != 0)
408 throw std::runtime_error("Context is in use");
409 if(!mBuffers.empty())
410 throw std::runtime_error("Trying to destroy a context with buffers");
412 if(mThread.joinable())
414 std::unique_lock<std::mutex> lock(mWakeMutex);
415 mQuitThread.store(true, std::memory_order_release);
416 lock.unlock();
417 mWakeThread.notify_all();
418 mThread.join();
421 alcDestroyContext(mContext);
422 mContext = nullptr;
424 mDevice->removeContext(this);
428 void ALContext::startBatch()
430 alcSuspendContext(mContext);
431 mIsBatching = true;
434 void ALContext::endBatch()
436 alcProcessContext(mContext);
437 mIsBatching = false;
441 Listener *ALContext::getListener()
443 return this;
447 SharedPtr<MessageHandler> ALContext::setMessageHandler(SharedPtr<MessageHandler> handler)
449 std::lock_guard<std::mutex> lock(mContextMutex);
450 mMessage.swap(handler);
451 return handler;
455 void ALContext::setAsyncWakeInterval(ALuint msec)
457 mWakeInterval.store(msec);
458 mWakeMutex.lock(); mWakeMutex.unlock();
459 mWakeThread.notify_all();
462 ALuint ALContext::getAsyncWakeInterval() const
464 return mWakeInterval.load();
468 SharedPtr<Decoder> ALContext::createDecoder(const String &name)
470 auto file = FileIOFactory::get().openFile(name);
471 if(file) return GetDecoder(name, std::move(file));
473 // Resource not found. Try to find a substitute.
474 if(!mMessage.get()) throw std::runtime_error("Failed to open "+name);
475 String oldname = name;
476 do {
477 String newname(mMessage->resourceNotFound(oldname));
478 if(newname.empty())
479 throw std::runtime_error("Failed to open "+oldname);
480 file = FileIOFactory::get().openFile(newname);
481 oldname = std::move(newname);
482 } while(!file);
484 return GetDecoder(oldname, std::move(file));
488 bool ALContext::isSupported(ChannelConfig channels, SampleType type) const
490 return GetFormat(channels, type) != AL_NONE;
494 Buffer *ALContext::getBuffer(const String &name)
496 CheckContext(this);
498 auto hasher = std::hash<String>();
499 auto iter = std::lower_bound(mBuffers.begin(), mBuffers.end(), hasher(name),
500 [hasher](const UniquePtr<ALBuffer> &lhs, size_t rhs) -> bool
501 { return hasher(lhs->getName()) < rhs; }
503 if(iter != mBuffers.end() && (*iter)->getName() == name)
505 // Ensure the buffer is loaded before returning. getBuffer guarantees
506 // the returned buffer is loaded.
507 ALBuffer *buffer = iter->get();
508 while(buffer->getLoadStatus() == BufferLoadStatus::Pending)
509 std::this_thread::yield();
510 return buffer;
512 // NOTE: 'iter' is used later to insert a new entry!
514 auto decoder = createDecoder(name);
516 ALuint srate = decoder->getFrequency();
517 ChannelConfig chans = decoder->getChannelConfig();
518 SampleType type = decoder->getSampleType();
519 ALuint frames = decoder->getLength();
521 Vector<ALbyte> data(FramesToBytes(frames, chans, type));
522 frames = decoder->read(&data[0], frames);
523 if(!frames) throw std::runtime_error("No samples for buffer");
524 data.resize(FramesToBytes(frames, chans, type));
526 std::pair<uint64_t,uint64_t> loop_pts = decoder->getLoopPoints();
527 if(loop_pts.first >= loop_pts.second)
528 loop_pts = std::make_pair(0, frames);
529 else
531 loop_pts.second = std::min<uint64_t>(loop_pts.second, frames);
532 loop_pts.first = std::min<uint64_t>(loop_pts.first, loop_pts.second-1);
535 // Get the format before calling the bufferLoading message handler, to
536 // ensure it's something OpenAL can handle.
537 ALenum format = GetFormat(chans, type);
538 if(format == AL_NONE)
540 std::stringstream sstr;
541 sstr<< "Format not supported ("<<GetSampleTypeName(type)<<", "<<GetChannelConfigName(chans)<<")";
542 throw std::runtime_error(sstr.str());
545 if(mMessage.get())
546 mMessage->bufferLoading(name, chans, type, srate, data);
548 alGetError();
549 ALuint bid = 0;
550 try {
551 alGenBuffers(1, &bid);
552 alBufferData(bid, format, &data[0], data.size(), srate);
553 if(hasExtension(SOFT_loop_points))
555 ALint pts[2]{(ALint)loop_pts.first, (ALint)loop_pts.second};
556 alBufferiv(bid, AL_LOOP_POINTS_SOFT, pts);
558 if(alGetError() != AL_NO_ERROR)
559 throw std::runtime_error("Failed to buffer data");
561 return mBuffers.insert(iter,
562 MakeUnique<ALBuffer>(this, bid, srate, chans, type, true, name)
563 )->get();
565 catch(...) {
566 alDeleteBuffers(1, &bid);
567 throw;
571 Buffer *ALContext::getBufferAsync(const String &name)
573 CheckContext(this);
575 auto hasher = std::hash<String>();
576 auto iter = std::lower_bound(mBuffers.begin(), mBuffers.end(), hasher(name),
577 [hasher](const UniquePtr<ALBuffer> &lhs, size_t rhs) -> bool
578 { return hasher(lhs->getName()) < rhs; }
580 if(iter != mBuffers.end() && (*iter)->getName() == name)
581 return iter->get();
582 // NOTE: 'iter' is used later to insert a new entry!
584 auto decoder = createDecoder(name);
586 ALuint srate = decoder->getFrequency();
587 ChannelConfig chans = decoder->getChannelConfig();
588 SampleType type = decoder->getSampleType();
589 ALuint frames = decoder->getLength();
590 if(!frames) throw std::runtime_error("No samples for buffer");
592 ALenum format = GetFormat(chans, type);
593 if(format == AL_NONE)
595 std::stringstream sstr;
596 sstr<< "Format not supported ("<<GetSampleTypeName(type)<<", "<<GetChannelConfigName(chans)<<")";
597 throw std::runtime_error(sstr.str());
600 alGetError();
601 ALuint bid = 0;
602 alGenBuffers(1, &bid);
603 if(alGetError() != AL_NO_ERROR)
604 throw std::runtime_error("Failed to buffer data");
606 auto buffer = MakeUnique<ALBuffer>(this, bid, srate, chans, type, false, name);
608 if(mThread.get_id() == std::thread::id())
609 mThread = std::thread(std::mem_fn(&ALContext::backgroundProc), this);
611 while(mPendingBuffers.write_space() == 0)
612 std::this_thread::yield();
614 RingBuffer::Data ringdata = mPendingBuffers.get_write_vector()[0];
615 new(ringdata.buf) PendingBuffer{name, buffer.get(), decoder, format, frames};
616 mPendingBuffers.write_advance(1);
617 mWakeMutex.lock(); mWakeMutex.unlock();
618 mWakeThread.notify_all();
620 return mBuffers.insert(iter, std::move(buffer))->get();
624 void ALContext::removeBuffer(const String &name)
626 CheckContext(this);
627 auto hasher = std::hash<String>();
628 auto iter = std::lower_bound(mBuffers.begin(), mBuffers.end(), hasher(name),
629 [hasher](const UniquePtr<ALBuffer> &lhs, size_t rhs) -> bool
630 { return hasher(lhs->getName()) < rhs; }
632 if(iter != mBuffers.end() && (*iter)->getName() == name)
634 (*iter)->cleanup();
635 mBuffers.erase(iter);
639 void ALContext::removeBuffer(Buffer *buffer)
641 removeBuffer(buffer->getName());
645 ALuint ALContext::getSourceId(ALuint maxprio)
647 CheckContext(this);
649 ALuint id = 0;
650 if(mSourceIds.empty())
652 alGetError();
653 alGenSources(1, &id);
654 if(alGetError() == AL_NO_ERROR)
655 return id;
657 ALSource *lowest = nullptr;
658 for(ALSource *src : mUsedSources)
660 if(src->getId() != 0 && (!lowest || src->getPriority() < lowest->getPriority()))
661 lowest = src;
663 if(lowest && lowest->getPriority() < maxprio)
665 lowest->makeStopped();
666 if(mMessage.get())
667 mMessage->sourceStopped(lowest, true);
670 if(mSourceIds.empty())
671 throw std::runtime_error("No available sources");
673 id = mSourceIds.top();
674 mSourceIds.pop();
675 return id;
679 Source *ALContext::createSource()
681 CheckContext(this);
683 ALSource *source;
684 if(!mFreeSources.empty())
686 source = mFreeSources.front();
687 mFreeSources.pop();
689 else
691 mAllSources.emplace_back(this);
692 source = &mAllSources.back();
694 auto iter = std::lower_bound(mUsedSources.begin(), mUsedSources.end(), source);
695 if(iter == mUsedSources.end() || *iter != source)
696 mUsedSources.insert(iter, source);
697 return source;
700 void ALContext::freeSource(ALSource *source)
702 auto iter = std::lower_bound(mUsedSources.begin(), mUsedSources.end(), source);
703 if(iter != mUsedSources.end() && *iter == source) mUsedSources.erase(iter);
704 mFreeSources.push(source);
708 void ALContext::addStream(ALSource *source)
710 std::lock_guard<std::mutex> lock(mSourceStreamMutex);
711 if(mThread.get_id() == std::thread::id())
712 mThread = std::thread(std::mem_fn(&ALContext::backgroundProc), this);
713 auto iter = std::lower_bound(mStreamingSources.begin(), mStreamingSources.end(), source);
714 if(iter == mStreamingSources.end() || *iter != source)
715 mStreamingSources.insert(iter, source);
718 void ALContext::removeStream(ALSource *source)
720 std::lock_guard<std::mutex> lock(mSourceStreamMutex);
721 auto iter = std::lower_bound(mStreamingSources.begin(), mStreamingSources.end(), source);
722 if(iter != mStreamingSources.end() && *iter == source)
723 mStreamingSources.erase(iter);
726 void ALContext::removeStreamNoLock(ALSource *source)
728 auto iter = std::lower_bound(mStreamingSources.begin(), mStreamingSources.end(), source);
729 if(iter != mStreamingSources.end() && *iter == source)
730 mStreamingSources.erase(iter);
734 AuxiliaryEffectSlot *ALContext::createAuxiliaryEffectSlot()
736 if(!hasExtension(EXT_EFX) || !alGenAuxiliaryEffectSlots)
737 throw std::runtime_error("AuxiliaryEffectSlots not supported");
738 CheckContext(this);
740 alGetError();
741 ALuint id = 0;
742 alGenAuxiliaryEffectSlots(1, &id);
743 if(alGetError() != AL_NO_ERROR)
744 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
745 try {
746 return new ALAuxiliaryEffectSlot(this, id);
748 catch(...) {
749 alDeleteAuxiliaryEffectSlots(1, &id);
750 throw;
755 Effect *ALContext::createEffect()
757 if(!hasExtension(EXT_EFX))
758 throw std::runtime_error("Effects not supported");
759 CheckContext(this);
761 alGetError();
762 ALuint id = 0;
763 alGenEffects(1, &id);
764 if(alGetError() != AL_NO_ERROR)
765 throw std::runtime_error("Failed to create Effect");
766 try {
767 return new ALEffect(this, id);
769 catch(...) {
770 alDeleteEffects(1, &id);
771 throw;
776 SourceGroup *ALContext::createSourceGroup(String name)
778 auto iter = std::lower_bound(mSourceGroups.begin(), mSourceGroups.end(), name,
779 [](const UniquePtr<ALSourceGroup> &lhs, const String &rhs) -> bool
780 { return lhs->getName() < rhs; }
782 if(iter != mSourceGroups.end() && (*iter)->getName() == name)
783 throw std::runtime_error("Duplicate source group name");
784 iter = mSourceGroups.insert(iter, MakeUnique<ALSourceGroup>(this, std::move(name)));
785 return iter->get();
788 SourceGroup *ALContext::getSourceGroup(const String &name)
790 auto iter = std::lower_bound(mSourceGroups.begin(), mSourceGroups.end(), name,
791 [](const UniquePtr<ALSourceGroup> &lhs, const String &rhs) -> bool
792 { return lhs->getName() < rhs; }
794 if(iter == mSourceGroups.end() || (*iter)->getName() != name)
795 throw std::runtime_error("Source group not found");
796 return iter->get();
799 void ALContext::freeSourceGroup(ALSourceGroup *group)
801 auto iter = std::lower_bound(mSourceGroups.begin(), mSourceGroups.end(), group->getName(),
802 [](const UniquePtr<ALSourceGroup> &lhs, const String &rhs) -> bool
803 { return lhs->getName() < rhs; }
805 if(iter != mSourceGroups.end() && iter->get() == group)
806 mSourceGroups.erase(iter);
810 void ALContext::setDopplerFactor(ALfloat factor)
812 if(!(factor >= 0.0f))
813 throw std::runtime_error("Doppler factor out of range");
814 CheckContext(this);
815 alDopplerFactor(factor);
819 void ALContext::setSpeedOfSound(ALfloat speed)
821 if(!(speed > 0.0f))
822 throw std::runtime_error("Speed of sound out of range");
823 CheckContext(this);
824 alSpeedOfSound(speed);
828 void ALContext::setDistanceModel(DistanceModel model)
830 CheckContext(this);
831 alDistanceModel((ALenum)model);
835 void ALContext::update()
837 CheckContext(this);
838 std::for_each(mUsedSources.begin(), mUsedSources.end(), std::mem_fn(&ALSource::updateNoCtxCheck));
839 if(!mWakeInterval.load())
841 // For performance reasons, don't wait for the thread's mutex. This
842 // should be called often enough to keep up with any and all streams
843 // regardless.
844 mWakeThread.notify_all();
847 if(hasExtension(EXT_disconnect) && mIsConnected)
849 ALCint connected;
850 alcGetIntegerv(alcGetContextsDevice(mContext), ALC_CONNECTED, 1, &connected);
851 if(!connected && mMessage.get()) mMessage->deviceDisconnected(mDevice);
852 mIsConnected = connected;
857 void ALContext::setGain(ALfloat gain)
859 if(!(gain >= 0.0f))
860 throw std::runtime_error("Gain out of range");
861 CheckContext(this);
862 alListenerf(AL_GAIN, gain);
866 void ALContext::setPosition(ALfloat x, ALfloat y, ALfloat z)
868 CheckContext(this);
869 alListener3f(AL_POSITION, x, y, z);
872 void ALContext::setPosition(const ALfloat *pos)
874 CheckContext(this);
875 alListenerfv(AL_POSITION, pos);
878 void ALContext::setVelocity(ALfloat x, ALfloat y, ALfloat z)
880 CheckContext(this);
881 alListener3f(AL_VELOCITY, x, y, z);
884 void ALContext::setVelocity(const ALfloat *vel)
886 CheckContext(this);
887 alListenerfv(AL_VELOCITY, vel);
890 void ALContext::setOrientation(ALfloat x1, ALfloat y1, ALfloat z1, ALfloat x2, ALfloat y2, ALfloat z2)
892 CheckContext(this);
893 ALfloat ori[6] = { x1, y1, z1, x2, y2, z2 };
894 alListenerfv(AL_ORIENTATION, ori);
897 void ALContext::setOrientation(const ALfloat *at, const ALfloat *up)
899 CheckContext(this);
900 ALfloat ori[6] = { at[0], at[1], at[2], up[0], up[1], up[2] };
901 alListenerfv(AL_ORIENTATION, ori);
904 void ALContext::setOrientation(const ALfloat *ori)
906 CheckContext(this);
907 alListenerfv(AL_ORIENTATION, ori);
910 void ALContext::setMetersPerUnit(ALfloat m_u)
912 if(!(m_u > 0.0f))
913 throw std::runtime_error("Invalid meters per unit");
914 CheckContext(this);
915 if(hasExtension(EXT_EFX))
916 alListenerf(AL_METERS_PER_UNIT, m_u);
920 void Context::MakeCurrent(Context *context)
922 ALContext *ctx = nullptr;
923 if(context)
925 ctx = cast<ALContext*>(context);
926 if(!ctx) throw std::runtime_error("Invalid context pointer");
928 ALContext::MakeCurrent(ctx);
931 Context *Context::GetCurrent()
933 return ALContext::GetCurrent();
936 void Context::MakeThreadCurrent(Context *context)
938 ALContext *ctx = nullptr;
939 if(context)
941 ctx = cast<ALContext*>(context);
942 if(!ctx) throw std::runtime_error("Invalid context pointer");
944 ALContext::MakeThreadCurrent(ctx);
947 Context *Context::GetThreadCurrent()
949 return ALContext::GetThreadCurrent();