19 #ifdef HAVE_VORBISFILE
20 #include "decoders/vorbisfile.hpp"
23 #include "decoders/flac.hpp"
26 #include "decoders/opusfile.hpp"
28 #ifdef HAVE_LIBSNDFILE
29 #include "decoders/sndfile.hpp"
32 #include "decoders/mpg123.hpp"
34 #include "decoders/wave.hpp"
36 #include "devicemanager.h"
40 #include "auxeffectslot.h"
42 #include <sourcegroup.h>
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
>() },
54 { "_alure_int_flac", MakeUnique
<FlacDecoderFactory
>() },
57 { "_alure_int_opus", MakeUnique
<OpusFileDecoderFactory
>() },
59 #ifdef HAVE_LIBSNDFILE
60 { "_alure_int_sndfile", MakeUnique
<SndFileDecoderFactory
>() },
63 { "_alure_int_mpg123", MakeUnique
<Mpg123DecoderFactory
>() },
67 static std::map
<String
,UniquePtr
<DecoderFactory
>> sDecoders
;
71 static SharedPtr
<Decoder
> GetDecoder(const String
&name
, UniquePtr
<std::istream
> &file
, T start
, T 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");
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
);
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
);
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
);
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
&)
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
;
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
;
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");
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
)
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");
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
);
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
326 RingBuffer::Data ringdata
= mPendingBuffers
.get_read_vector()[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);
336 std::unique_lock
<std::mutex
> wakelock(mWakeMutex
);
337 if(!mQuitThread
.load(std::memory_order_acquire
) && mPendingBuffers
.read_space() == 0)
341 ALuint interval
= mWakeInterval
.load();
343 mWakeThread
.wait(wakelock
);
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
);
354 while(!mQuitThread
.load(std::memory_order_acquire
) &&
355 alcGetCurrentContext() != getContext())
356 mWakeThread
.wait(ctxlock
);
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()
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
);
417 mWakeThread
.notify_all();
421 alcDestroyContext(mContext
);
424 mDevice
->removeContext(this);
428 void ALContext::startBatch()
430 alcSuspendContext(mContext
);
434 void ALContext::endBatch()
436 alcProcessContext(mContext
);
441 Listener
*ALContext::getListener()
447 SharedPtr
<MessageHandler
> ALContext::setMessageHandler(SharedPtr
<MessageHandler
> handler
)
449 std::lock_guard
<std::mutex
> lock(mContextMutex
);
450 mMessage
.swap(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
;
477 String
newname(mMessage
->resourceNotFound(oldname
));
479 throw std::runtime_error("Failed to open "+oldname
);
480 file
= FileIOFactory::get().openFile(newname
);
481 oldname
= std::move(newname
);
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
)
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();
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
);
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());
546 mMessage
->bufferLoading(name
, chans
, type
, srate
, data
);
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
)
566 alDeleteBuffers(1, &bid
);
571 Buffer
*ALContext::getBufferAsync(const String
&name
)
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
)
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());
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
)
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
)
635 mBuffers
.erase(iter
);
639 void ALContext::removeBuffer(Buffer
*buffer
)
641 removeBuffer(buffer
->getName());
645 ALuint
ALContext::getSourceId(ALuint maxprio
)
650 if(mSourceIds
.empty())
653 alGenSources(1, &id
);
654 if(alGetError() == AL_NO_ERROR
)
657 ALSource
*lowest
= nullptr;
658 for(ALSource
*src
: mUsedSources
)
660 if(src
->getId() != 0 && (!lowest
|| src
->getPriority() < lowest
->getPriority()))
663 if(lowest
&& lowest
->getPriority() < maxprio
)
665 lowest
->makeStopped();
667 mMessage
->sourceStopped(lowest
, true);
670 if(mSourceIds
.empty())
671 throw std::runtime_error("No available sources");
673 id
= mSourceIds
.top();
679 Source
*ALContext::createSource()
684 if(!mFreeSources
.empty())
686 source
= mFreeSources
.front();
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
);
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");
742 alGenAuxiliaryEffectSlots(1, &id
);
743 if(alGetError() != AL_NO_ERROR
)
744 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
746 return new ALAuxiliaryEffectSlot(this, id
);
749 alDeleteAuxiliaryEffectSlots(1, &id
);
755 Effect
*ALContext::createEffect()
757 if(!hasExtension(EXT_EFX
))
758 throw std::runtime_error("Effects not supported");
763 alGenEffects(1, &id
);
764 if(alGetError() != AL_NO_ERROR
)
765 throw std::runtime_error("Failed to create Effect");
767 return new ALEffect(this, id
);
770 alDeleteEffects(1, &id
);
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
)));
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");
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");
815 alDopplerFactor(factor
);
819 void ALContext::setSpeedOfSound(ALfloat speed
)
822 throw std::runtime_error("Speed of sound out of range");
824 alSpeedOfSound(speed
);
828 void ALContext::setDistanceModel(DistanceModel model
)
831 alDistanceModel((ALenum
)model
);
835 void ALContext::update()
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
844 mWakeThread
.notify_all();
847 if(hasExtension(EXT_disconnect
) && mIsConnected
)
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
)
860 throw std::runtime_error("Gain out of range");
862 alListenerf(AL_GAIN
, gain
);
866 void ALContext::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
869 alListener3f(AL_POSITION
, x
, y
, z
);
872 void ALContext::setPosition(const ALfloat
*pos
)
875 alListenerfv(AL_POSITION
, pos
);
878 void ALContext::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
881 alListener3f(AL_VELOCITY
, x
, y
, z
);
884 void ALContext::setVelocity(const ALfloat
*vel
)
887 alListenerfv(AL_VELOCITY
, vel
);
890 void ALContext::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
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
)
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
)
907 alListenerfv(AL_ORIENTATION
, ori
);
910 void ALContext::setMetersPerUnit(ALfloat m_u
)
913 throw std::runtime_error("Invalid meters per unit");
915 if(hasExtension(EXT_EFX
))
916 alListenerf(AL_METERS_PER_UNIT
, m_u
);
920 void Context::MakeCurrent(Context
*context
)
922 ALContext
*ctx
= nullptr;
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;
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();