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
*)
154 void MessageHandler::sourceForceStopped(Source
*)
158 void MessageHandler::bufferLoading(const String
&, ChannelConfig
, SampleType
, ALuint
, const Vector
<ALbyte
>&)
162 String
MessageHandler::resourceNotFound(const String
&)
169 static inline void LoadALFunc(T
**func
, const char *name
)
170 { *func
= reinterpret_cast<T
*>(alGetProcAddress(name
)); }
172 static void LoadNothing(ALContext
*) { }
174 static void LoadEFX(ALContext
*ctx
)
176 LoadALFunc(&ctx
->alGenEffects
, "alGenEffects");
177 LoadALFunc(&ctx
->alDeleteEffects
, "alDeleteEffects");
178 LoadALFunc(&ctx
->alIsEffect
, "alIsEffect");
179 LoadALFunc(&ctx
->alEffecti
, "alEffecti");
180 LoadALFunc(&ctx
->alEffectiv
, "alEffectiv");
181 LoadALFunc(&ctx
->alEffectf
, "alEffectf");
182 LoadALFunc(&ctx
->alEffectfv
, "alEffectfv");
183 LoadALFunc(&ctx
->alGetEffecti
, "alGetEffecti");
184 LoadALFunc(&ctx
->alGetEffectiv
, "alGetEffectiv");
185 LoadALFunc(&ctx
->alGetEffectf
, "alGetEffectf");
186 LoadALFunc(&ctx
->alGetEffectfv
, "alGetEffectfv");
188 LoadALFunc(&ctx
->alGenFilters
, "alGenFilters");
189 LoadALFunc(&ctx
->alDeleteFilters
, "alDeleteFilters");
190 LoadALFunc(&ctx
->alIsFilter
, "alIsFilter");
191 LoadALFunc(&ctx
->alFilteri
, "alFilteri");
192 LoadALFunc(&ctx
->alFilteriv
, "alFilteriv");
193 LoadALFunc(&ctx
->alFilterf
, "alFilterf");
194 LoadALFunc(&ctx
->alFilterfv
, "alFilterfv");
195 LoadALFunc(&ctx
->alGetFilteri
, "alGetFilteri");
196 LoadALFunc(&ctx
->alGetFilteriv
, "alGetFilteriv");
197 LoadALFunc(&ctx
->alGetFilterf
, "alGetFilterf");
198 LoadALFunc(&ctx
->alGetFilterfv
, "alGetFilterfv");
200 LoadALFunc(&ctx
->alGenAuxiliaryEffectSlots
, "alGenAuxiliaryEffectSlots");
201 LoadALFunc(&ctx
->alDeleteAuxiliaryEffectSlots
, "alDeleteAuxiliaryEffectSlots");
202 LoadALFunc(&ctx
->alIsAuxiliaryEffectSlot
, "alIsAuxiliaryEffectSlot");
203 LoadALFunc(&ctx
->alAuxiliaryEffectSloti
, "alAuxiliaryEffectSloti");
204 LoadALFunc(&ctx
->alAuxiliaryEffectSlotiv
, "alAuxiliaryEffectSlotiv");
205 LoadALFunc(&ctx
->alAuxiliaryEffectSlotf
, "alAuxiliaryEffectSlotf");
206 LoadALFunc(&ctx
->alAuxiliaryEffectSlotfv
, "alAuxiliaryEffectSlotfv");
207 LoadALFunc(&ctx
->alGetAuxiliaryEffectSloti
, "alGetAuxiliaryEffectSloti");
208 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotiv
, "alGetAuxiliaryEffectSlotiv");
209 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotf
, "alGetAuxiliaryEffectSlotf");
210 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotfv
, "alGetAuxiliaryEffectSlotfv");
213 static void LoadSourceLatency(ALContext
*ctx
)
215 LoadALFunc(&ctx
->alGetSourcei64vSOFT
, "alGetSourcei64vSOFT");
218 static const struct {
219 enum ALExtension extension
;
221 void (&loader
)(ALContext
*);
222 } ALExtensionList
[] = {
223 { EXT_EFX
, "ALC_EXT_EFX", LoadEFX
},
225 { EXT_FLOAT32
, "AL_EXT_FLOAT32", LoadNothing
},
226 { EXT_MCFORMATS
, "AL_EXT_MCFORMATS", LoadNothing
},
227 { EXT_BFORMAT
, "AL_EXT_BFORMAT", LoadNothing
},
229 { EXT_MULAW
, "AL_EXT_MULAW", LoadNothing
},
230 { EXT_MULAW_MCFORMATS
, "AL_EXT_MULAW_MCFORMATS", LoadNothing
},
231 { EXT_MULAW_BFORMAT
, "AL_EXT_MULAW_BFORMAT", LoadNothing
},
233 { SOFT_loop_points
, "AL_SOFT_loop_points", LoadNothing
},
234 { SOFT_source_latency
, "AL_SOFT_source_latency", LoadSourceLatency
},
236 { EXT_disconnect
, "ALC_EXT_disconnect", LoadNothing
},
238 { EXT_SOURCE_RADIUS
, "AL_EXT_SOURCE_RADIUS", LoadNothing
},
239 { EXT_STEREO_ANGLES
, "AL_EXT_STEREO_ANGLES", LoadNothing
},
243 ALContext
*ALContext::sCurrentCtx
= nullptr;
244 thread_local ALContext
*ALContext::sThreadCurrentCtx
= nullptr;
246 void ALContext::MakeCurrent(ALContext
*context
)
248 std::unique_lock
<std::mutex
> lock1
, lock2
;
250 lock1
= std::unique_lock
<std::mutex
>(sCurrentCtx
->mContextMutex
);
251 if(context
&& context
!= sCurrentCtx
)
252 lock2
= std::unique_lock
<std::mutex
>(context
->mContextMutex
);
254 if(alcMakeContextCurrent(context
? context
->getContext() : 0) == ALC_FALSE
)
255 throw std::runtime_error("Call to alcMakeContextCurrent failed");
259 std::call_once(context
->mSetExts
, std::mem_fn(&ALContext::setupExts
), context
);
261 std::swap(sCurrentCtx
, context
);
262 if(context
) context
->decRef();
264 if(sThreadCurrentCtx
)
265 sThreadCurrentCtx
->decRef();
266 sThreadCurrentCtx
= 0;
268 if(sCurrentCtx
&& sCurrentCtx
!= context
)
271 sCurrentCtx
->mWakeThread
.notify_all();
275 void ALContext::MakeThreadCurrent(ALContext
*context
)
277 if(!ALDeviceManager::SetThreadContext
)
278 throw std::runtime_error("Thread-local contexts unsupported");
279 if(ALDeviceManager::SetThreadContext(context
? context
->getContext() : nullptr) == ALC_FALSE
)
280 throw std::runtime_error("Call to alcSetThreadContext failed");
284 std::call_once(context
->mSetExts
, std::mem_fn(&ALContext::setupExts
), context
);
286 if(sThreadCurrentCtx
)
287 sThreadCurrentCtx
->decRef();
288 sThreadCurrentCtx
= context
;
291 void ALContext::setupExts()
293 ALCdevice
*device
= mDevice
->getDevice();
294 std::fill(std::begin(mHasExt
), std::end(mHasExt
), false);
295 for(const auto &entry
: ALExtensionList
)
297 mHasExt
[entry
.extension
] = (strncmp(entry
.name
, "ALC", 3) == 0) ?
298 alcIsExtensionPresent(device
, entry
.name
) :
299 alIsExtensionPresent(entry
.name
);
300 if(mHasExt
[entry
.extension
]) entry
.loader(this);
305 void ALContext::backgroundProc()
307 if(ALDeviceManager::SetThreadContext
&& mDevice
->hasExtension(EXT_thread_local_context
))
308 ALDeviceManager::SetThreadContext(getContext());
310 std::chrono::steady_clock::time_point basetime
= std::chrono::steady_clock::now();
311 std::chrono::milliseconds
waketime(0);
312 std::unique_lock
<std::mutex
> ctxlock(mContextMutex
);
313 while(!mQuitThread
.load(std::memory_order_acquire
))
316 std::lock_guard
<std::mutex
> srclock(mSourceStreamMutex
);
317 auto source
= mStreamingSources
.begin();
318 while(source
!= mStreamingSources
.end())
320 if(!(*source
)->updateAsync())
321 source
= mStreamingSources
.erase(source
);
327 // Only do one pending buffer at a time. In case there's several large
328 // buffers to load, we still need to process streaming sources so they
330 RingBuffer::Data ringdata
= mPendingBuffers
.get_read_vector()[0];
333 PendingBuffer
*pb
= reinterpret_cast<PendingBuffer
*>(ringdata
.buf
);
334 pb
->mBuffer
->load(pb
->mFrames
, pb
->mFormat
, pb
->mDecoder
, pb
->mName
, this);
335 pb
->~PendingBuffer();
336 mPendingBuffers
.read_advance(1);
340 std::unique_lock
<std::mutex
> wakelock(mWakeMutex
);
341 if(!mQuitThread
.load(std::memory_order_acquire
) && mPendingBuffers
.read_space() == 0)
345 ALuint interval
= mWakeInterval
.load();
347 mWakeThread
.wait(wakelock
);
350 auto now
= std::chrono::steady_clock::now() - basetime
;
351 auto duration
= std::chrono::milliseconds(interval
);
352 while((waketime
- now
).count() <= 0) waketime
+= duration
;
353 mWakeThread
.wait_until(wakelock
, waketime
+ basetime
);
358 while(!mQuitThread
.load(std::memory_order_acquire
) &&
359 alcGetCurrentContext() != getContext())
360 mWakeThread
.wait(ctxlock
);
365 if(ALDeviceManager::SetThreadContext
)
366 ALDeviceManager::SetThreadContext(nullptr);
370 ALContext::ALContext(ALCcontext
*context
, ALDevice
*device
)
371 : mListener(this), mContext(context
), mDevice(device
), mRefs(0),
372 mHasExt
{false}, mPendingBuffers(16, sizeof(PendingBuffer
)),
373 mWakeInterval(0), mQuitThread(false), mIsConnected(true), mIsBatching(false),
374 alGetSourcei64vSOFT(0),
375 alGenEffects(0), alDeleteEffects(0), alIsEffect(0),
376 alEffecti(0), alEffectiv(0), alEffectf(0), alEffectfv(0),
377 alGetEffecti(0), alGetEffectiv(0), alGetEffectf(0), alGetEffectfv(0),
378 alGenFilters(0), alDeleteFilters(0), alIsFilter(0),
379 alFilteri(0), alFilteriv(0), alFilterf(0), alFilterfv(0),
380 alGetFilteri(0), alGetFilteriv(0), alGetFilterf(0), alGetFilterfv(0),
381 alGenAuxiliaryEffectSlots(0), alDeleteAuxiliaryEffectSlots(0), alIsAuxiliaryEffectSlot(0),
382 alAuxiliaryEffectSloti(0), alAuxiliaryEffectSlotiv(0), alAuxiliaryEffectSlotf(0), alAuxiliaryEffectSlotfv(0),
383 alGetAuxiliaryEffectSloti(0), alGetAuxiliaryEffectSlotiv(0), alGetAuxiliaryEffectSlotf(0), alGetAuxiliaryEffectSlotfv(0)
387 ALContext::~ALContext()
389 auto ringdata
= mPendingBuffers
.get_read_vector();
390 if(ringdata
[0].len
> 0)
392 PendingBuffer
*pb
= reinterpret_cast<PendingBuffer
*>(ringdata
[0].buf
);
393 for(size_t i
= 0;i
< ringdata
[0].len
;i
++)
394 pb
[i
].~PendingBuffer();
395 pb
= reinterpret_cast<PendingBuffer
*>(ringdata
[1].buf
);
396 for(size_t i
= 0;i
< ringdata
[1].len
;i
++)
397 pb
[i
].~PendingBuffer();
399 mPendingBuffers
.read_advance(ringdata
[0].len
+ ringdata
[1].len
);
404 Device
ALContext::getDevice()
406 return Device(mDevice
);
409 void ALContext::destroy()
411 if(mRefs
.load() != 0)
412 throw std::runtime_error("Context is in use");
413 if(!mBuffers
.empty())
414 throw std::runtime_error("Trying to destroy a context with buffers");
416 if(mThread
.joinable())
418 std::unique_lock
<std::mutex
> lock(mWakeMutex
);
419 mQuitThread
.store(true, std::memory_order_release
);
421 mWakeThread
.notify_all();
425 alcDestroyContext(mContext
);
428 mDevice
->removeContext(this);
432 void ALContext::startBatch()
434 alcSuspendContext(mContext
);
438 void ALContext::endBatch()
440 alcProcessContext(mContext
);
445 Listener
*ALContext::getListener()
451 SharedPtr
<MessageHandler
> ALContext::setMessageHandler(SharedPtr
<MessageHandler
> handler
)
453 std::lock_guard
<std::mutex
> lock(mContextMutex
);
454 mMessage
.swap(handler
);
459 void ALContext::setAsyncWakeInterval(ALuint msec
)
461 mWakeInterval
.store(msec
);
462 mWakeMutex
.lock(); mWakeMutex
.unlock();
463 mWakeThread
.notify_all();
466 ALuint
ALContext::getAsyncWakeInterval() const
468 return mWakeInterval
.load();
472 SharedPtr
<Decoder
> ALContext::createDecoder(const String
&name
)
474 auto file
= FileIOFactory::get().openFile(name
);
475 if(file
) return GetDecoder(name
, std::move(file
));
477 // Resource not found. Try to find a substitute.
478 if(!mMessage
.get()) throw std::runtime_error("Failed to open "+name
);
479 String oldname
= name
;
481 String
newname(mMessage
->resourceNotFound(oldname
));
483 throw std::runtime_error("Failed to open "+oldname
);
484 file
= FileIOFactory::get().openFile(newname
);
485 oldname
= std::move(newname
);
488 return GetDecoder(oldname
, std::move(file
));
492 bool ALContext::isSupported(ChannelConfig channels
, SampleType type
) const
494 return GetFormat(channels
, type
) != AL_NONE
;
498 Buffer
ALContext::getBuffer(const String
&name
)
502 auto hasher
= std::hash
<String
>();
503 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
504 [hasher
](const UniquePtr
<ALBuffer
> &lhs
, size_t rhs
) -> bool
505 { return hasher(lhs
->getName()) < rhs
; }
507 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
509 // Ensure the buffer is loaded before returning. getBuffer guarantees
510 // the returned buffer is loaded.
511 ALBuffer
*buffer
= iter
->get();
512 while(buffer
->getLoadStatus() == BufferLoadStatus::Pending
)
513 std::this_thread::yield();
514 return Buffer(buffer
);
516 // NOTE: 'iter' is used later to insert a new entry!
518 auto decoder
= createDecoder(name
);
520 ALuint srate
= decoder
->getFrequency();
521 ChannelConfig chans
= decoder
->getChannelConfig();
522 SampleType type
= decoder
->getSampleType();
523 ALuint frames
= decoder
->getLength();
525 Vector
<ALbyte
> data(FramesToBytes(frames
, chans
, type
));
526 frames
= decoder
->read(&data
[0], frames
);
527 if(!frames
) throw std::runtime_error("No samples for buffer");
528 data
.resize(FramesToBytes(frames
, chans
, type
));
530 std::pair
<uint64_t,uint64_t> loop_pts
= decoder
->getLoopPoints();
531 if(loop_pts
.first
>= loop_pts
.second
)
532 loop_pts
= std::make_pair(0, frames
);
535 loop_pts
.second
= std::min
<uint64_t>(loop_pts
.second
, frames
);
536 loop_pts
.first
= std::min
<uint64_t>(loop_pts
.first
, loop_pts
.second
-1);
539 // Get the format before calling the bufferLoading message handler, to
540 // ensure it's something OpenAL can handle.
541 ALenum format
= GetFormat(chans
, type
);
542 if(format
== AL_NONE
)
544 std::stringstream sstr
;
545 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
546 throw std::runtime_error(sstr
.str());
550 mMessage
->bufferLoading(name
, chans
, type
, srate
, data
);
555 alGenBuffers(1, &bid
);
556 alBufferData(bid
, format
, &data
[0], data
.size(), srate
);
557 if(hasExtension(SOFT_loop_points
))
559 ALint pts
[2]{(ALint
)loop_pts
.first
, (ALint
)loop_pts
.second
};
560 alBufferiv(bid
, AL_LOOP_POINTS_SOFT
, pts
);
562 if(alGetError() != AL_NO_ERROR
)
563 throw std::runtime_error("Failed to buffer data");
565 return Buffer(mBuffers
.insert(iter
,
566 MakeUnique
<ALBuffer
>(this, bid
, srate
, chans
, type
, true, name
)
570 alDeleteBuffers(1, &bid
);
575 Buffer
ALContext::getBufferAsync(const String
&name
)
579 auto hasher
= std::hash
<String
>();
580 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
581 [hasher
](const UniquePtr
<ALBuffer
> &lhs
, size_t rhs
) -> bool
582 { return hasher(lhs
->getName()) < rhs
; }
584 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
585 return Buffer(iter
->get());
586 // NOTE: 'iter' is used later to insert a new entry!
588 auto decoder
= createDecoder(name
);
590 ALuint srate
= decoder
->getFrequency();
591 ChannelConfig chans
= decoder
->getChannelConfig();
592 SampleType type
= decoder
->getSampleType();
593 ALuint frames
= decoder
->getLength();
594 if(!frames
) throw std::runtime_error("No samples for buffer");
596 ALenum format
= GetFormat(chans
, type
);
597 if(format
== AL_NONE
)
599 std::stringstream sstr
;
600 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
601 throw std::runtime_error(sstr
.str());
606 alGenBuffers(1, &bid
);
607 if(alGetError() != AL_NO_ERROR
)
608 throw std::runtime_error("Failed to buffer data");
610 auto buffer
= MakeUnique
<ALBuffer
>(this, bid
, srate
, chans
, type
, false, name
);
612 if(mThread
.get_id() == std::thread::id())
613 mThread
= std::thread(std::mem_fn(&ALContext::backgroundProc
), this);
615 while(mPendingBuffers
.write_space() == 0)
616 std::this_thread::yield();
618 RingBuffer::Data ringdata
= mPendingBuffers
.get_write_vector()[0];
619 new(ringdata
.buf
) PendingBuffer
{name
, buffer
.get(), decoder
, format
, frames
};
620 mPendingBuffers
.write_advance(1);
621 mWakeMutex
.lock(); mWakeMutex
.unlock();
622 mWakeThread
.notify_all();
624 return Buffer(mBuffers
.insert(iter
, std::move(buffer
))->get());
628 void ALContext::removeBuffer(const String
&name
)
631 auto hasher
= std::hash
<String
>();
632 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
633 [hasher
](const UniquePtr
<ALBuffer
> &lhs
, size_t rhs
) -> bool
634 { return hasher(lhs
->getName()) < rhs
; }
636 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
639 mBuffers
.erase(iter
);
643 void ALContext::removeBuffer(Buffer buffer
)
645 removeBuffer(buffer
.getName());
649 ALuint
ALContext::getSourceId(ALuint maxprio
)
654 if(mSourceIds
.empty())
657 alGenSources(1, &id
);
658 if(alGetError() == AL_NO_ERROR
)
661 ALSource
*lowest
= nullptr;
662 for(ALSource
*src
: mUsedSources
)
664 if(src
->getId() != 0 && (!lowest
|| src
->getPriority() < lowest
->getPriority()))
667 if(lowest
&& lowest
->getPriority() < maxprio
)
669 lowest
->makeStopped();
671 mMessage
->sourceForceStopped(lowest
);
674 if(mSourceIds
.empty())
675 throw std::runtime_error("No available sources");
677 id
= mSourceIds
.top();
683 Source
*ALContext::createSource()
688 if(!mFreeSources
.empty())
690 source
= mFreeSources
.front();
695 mAllSources
.emplace_back(this);
696 source
= &mAllSources
.back();
698 auto iter
= std::lower_bound(mUsedSources
.begin(), mUsedSources
.end(), source
);
699 if(iter
== mUsedSources
.end() || *iter
!= source
)
700 mUsedSources
.insert(iter
, source
);
704 void ALContext::freeSource(ALSource
*source
)
706 auto iter
= std::lower_bound(mUsedSources
.begin(), mUsedSources
.end(), source
);
707 if(iter
!= mUsedSources
.end() && *iter
== source
) mUsedSources
.erase(iter
);
708 mFreeSources
.push(source
);
712 void ALContext::addStream(ALSource
*source
)
714 std::lock_guard
<std::mutex
> lock(mSourceStreamMutex
);
715 if(mThread
.get_id() == std::thread::id())
716 mThread
= std::thread(std::mem_fn(&ALContext::backgroundProc
), this);
717 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
718 if(iter
== mStreamingSources
.end() || *iter
!= source
)
719 mStreamingSources
.insert(iter
, source
);
722 void ALContext::removeStream(ALSource
*source
)
724 std::lock_guard
<std::mutex
> lock(mSourceStreamMutex
);
725 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
726 if(iter
!= mStreamingSources
.end() && *iter
== source
)
727 mStreamingSources
.erase(iter
);
730 void ALContext::removeStreamNoLock(ALSource
*source
)
732 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
733 if(iter
!= mStreamingSources
.end() && *iter
== source
)
734 mStreamingSources
.erase(iter
);
738 AuxiliaryEffectSlot
*ALContext::createAuxiliaryEffectSlot()
740 if(!hasExtension(EXT_EFX
) || !alGenAuxiliaryEffectSlots
)
741 throw std::runtime_error("AuxiliaryEffectSlots not supported");
746 alGenAuxiliaryEffectSlots(1, &id
);
747 if(alGetError() != AL_NO_ERROR
)
748 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
750 return new ALAuxiliaryEffectSlot(this, id
);
753 alDeleteAuxiliaryEffectSlots(1, &id
);
759 Effect
*ALContext::createEffect()
761 if(!hasExtension(EXT_EFX
))
762 throw std::runtime_error("Effects not supported");
767 alGenEffects(1, &id
);
768 if(alGetError() != AL_NO_ERROR
)
769 throw std::runtime_error("Failed to create Effect");
771 return new ALEffect(this, id
);
774 alDeleteEffects(1, &id
);
780 SourceGroup
*ALContext::createSourceGroup(String name
)
782 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), name
,
783 [](const UniquePtr
<ALSourceGroup
> &lhs
, const String
&rhs
) -> bool
784 { return lhs
->getName() < rhs
; }
786 if(iter
!= mSourceGroups
.end() && (*iter
)->getName() == name
)
787 throw std::runtime_error("Duplicate source group name");
788 iter
= mSourceGroups
.insert(iter
, MakeUnique
<ALSourceGroup
>(this, std::move(name
)));
792 SourceGroup
*ALContext::getSourceGroup(const String
&name
)
794 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), name
,
795 [](const UniquePtr
<ALSourceGroup
> &lhs
, const String
&rhs
) -> bool
796 { return lhs
->getName() < rhs
; }
798 if(iter
== mSourceGroups
.end() || (*iter
)->getName() != name
)
799 throw std::runtime_error("Source group not found");
803 void ALContext::freeSourceGroup(ALSourceGroup
*group
)
805 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), group
->getName(),
806 [](const UniquePtr
<ALSourceGroup
> &lhs
, const String
&rhs
) -> bool
807 { return lhs
->getName() < rhs
; }
809 if(iter
!= mSourceGroups
.end() && iter
->get() == group
)
810 mSourceGroups
.erase(iter
);
814 void ALContext::setDopplerFactor(ALfloat factor
)
816 if(!(factor
>= 0.0f
))
817 throw std::runtime_error("Doppler factor out of range");
819 alDopplerFactor(factor
);
823 void ALContext::setSpeedOfSound(ALfloat speed
)
826 throw std::runtime_error("Speed of sound out of range");
828 alSpeedOfSound(speed
);
832 void ALContext::setDistanceModel(DistanceModel model
)
835 alDistanceModel((ALenum
)model
);
839 void ALContext::update()
842 std::for_each(mUsedSources
.begin(), mUsedSources
.end(), std::mem_fn(&ALSource::updateNoCtxCheck
));
843 if(!mWakeInterval
.load())
845 // For performance reasons, don't wait for the thread's mutex. This
846 // should be called often enough to keep up with any and all streams
848 mWakeThread
.notify_all();
851 if(hasExtension(EXT_disconnect
) && mIsConnected
)
854 alcGetIntegerv(alcGetContextsDevice(mContext
), ALC_CONNECTED
, 1, &connected
);
855 if(!connected
&& mMessage
.get()) mMessage
->deviceDisconnected(Device(mDevice
));
856 mIsConnected
= connected
;
860 void Context::destroy()
865 DECL_THUNK0(Device
, Context
, getDevice
,)
866 DECL_THUNK0(void, Context
, startBatch
,)
867 DECL_THUNK0(void, Context
, endBatch
,)
868 DECL_THUNK0(Listener
*, Context
, getListener
,)
869 DECL_THUNK1(SharedPtr
<MessageHandler
>, Context
, setMessageHandler
,, SharedPtr
<MessageHandler
>)
870 DECL_THUNK0(SharedPtr
<MessageHandler
>, Context
, getMessageHandler
, const)
871 DECL_THUNK1(void, Context
, setAsyncWakeInterval
,, ALuint
)
872 DECL_THUNK0(ALuint
, Context
, getAsyncWakeInterval
, const)
873 DECL_THUNK1(SharedPtr
<Decoder
>, Context
, createDecoder
,, const String
&)
874 DECL_THUNK2(bool, Context
, isSupported
, const, ChannelConfig
, SampleType
)
875 DECL_THUNK1(Buffer
, Context
, getBuffer
,, const String
&)
876 DECL_THUNK1(Buffer
, Context
, getBufferAsync
,, const String
&)
877 DECL_THUNK1(void, Context
, removeBuffer
,, const String
&)
878 DECL_THUNK1(void, Context
, removeBuffer
,, Buffer
)
879 DECL_THUNK0(Source
*, Context
, createSource
,)
880 DECL_THUNK0(AuxiliaryEffectSlot
*, Context
, createAuxiliaryEffectSlot
,)
881 DECL_THUNK0(Effect
*, Context
, createEffect
,)
882 DECL_THUNK1(SourceGroup
*, Context
, createSourceGroup
,, String
)
883 DECL_THUNK1(SourceGroup
*, Context
, getSourceGroup
,, const String
&)
884 DECL_THUNK1(void, Context
, setDopplerFactor
,, ALfloat
)
885 DECL_THUNK1(void, Context
, setSpeedOfSound
,, ALfloat
)
886 DECL_THUNK1(void, Context
, setDistanceModel
,, DistanceModel
)
887 DECL_THUNK0(void, Context
, update
,)
890 void Context::MakeCurrent(Context context
)
891 { ALContext::MakeCurrent(context
.pImpl
); }
893 void Context::MakeCurrent(std::nullptr_t
)
894 { ALContext::MakeCurrent(nullptr); }
896 Context
Context::GetCurrent()
897 { return Context(ALContext::GetCurrent()); }
899 void Context::MakeThreadCurrent(Context context
)
900 { ALContext::MakeThreadCurrent(context
.pImpl
); }
902 void Context::MakeThreadCurrent(std::nullptr_t
)
903 { ALContext::MakeThreadCurrent(nullptr); }
905 Context
Context::GetThreadCurrent()
906 { return Context(ALContext::GetThreadCurrent()); }
909 void ALListener::setGain(ALfloat gain
)
912 throw std::runtime_error("Gain out of range");
913 CheckContext(mContext
);
914 alListenerf(AL_GAIN
, gain
);
918 void ALListener::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
920 CheckContext(mContext
);
921 alListener3f(AL_POSITION
, x
, y
, z
);
924 void ALListener::setPosition(const ALfloat
*pos
)
926 CheckContext(mContext
);
927 alListenerfv(AL_POSITION
, pos
);
930 void ALListener::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
932 CheckContext(mContext
);
933 alListener3f(AL_VELOCITY
, x
, y
, z
);
936 void ALListener::setVelocity(const ALfloat
*vel
)
938 CheckContext(mContext
);
939 alListenerfv(AL_VELOCITY
, vel
);
942 void ALListener::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
944 CheckContext(mContext
);
945 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
946 alListenerfv(AL_ORIENTATION
, ori
);
949 void ALListener::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
951 CheckContext(mContext
);
952 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
953 alListenerfv(AL_ORIENTATION
, ori
);
956 void ALListener::setOrientation(const ALfloat
*ori
)
958 CheckContext(mContext
);
959 alListenerfv(AL_ORIENTATION
, ori
);
962 void ALListener::setMetersPerUnit(ALfloat m_u
)
965 throw std::runtime_error("Invalid meters per unit");
966 CheckContext(mContext
);
967 if(mContext
->hasExtension(EXT_EFX
))
968 alListenerf(AL_METERS_PER_UNIT
, m_u
);