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"
45 #define WIN32_LEAN_AND_MEAN
52 // Implements a FNV-1a hash for StringView. NOTE: This is *NOT* guaranteed
53 // compatible with std::hash<String>! The standard does not give any specific
54 // hash implementation, nor a way for applications to access the same hash
55 // function as std::string (short of copying into a string and hashing that).
56 // So if you need Strings and StringViews to result in the same hash for the
57 // same set of characters, hash StringViews created from the Strings.
59 struct hash
<alure::StringView
> {
60 size_t operator()(const alure::StringView
&str
) const noexcept
62 using traits_type
= alure::StringView::traits_type
;
64 if /*constexpr*/ (sizeof(size_t) == 8)
66 static constexpr size_t hash_offset
= 0xcbf29ce484222325;
67 static constexpr size_t hash_prime
= 0x100000001b3;
69 size_t val
= hash_offset
;
71 val
= (val
^traits_type::to_int_type(ch
)) * hash_prime
;
76 static constexpr size_t hash_offset
= 0x811c9dc5;
77 static constexpr size_t hash_prime
= 0x1000193;
79 size_t val
= hash_offset
;
81 val
= (val
^traits_type::to_int_type(ch
)) * hash_prime
;
92 // Global mutex to protect global context changes
93 std::mutex mGlobalCtxMutex
;
96 // Windows' std::ifstream fails with non-ANSI paths since the standard only
97 // specifies names using const char* (or std::string). MSVC has a non-standard
98 // extension using const wchar_t* (or std::wstring?) to handle Unicode paths,
99 // but not all Windows compilers support it. So we have to make our own istream
100 // that accepts UTF-8 paths and forwards to Unicode-aware I/O functions.
101 class StreamBuf final
: public std::streambuf
{
102 alure::Array
<char_type
,4096> mBuffer
;
105 int_type
underflow() override
107 if(mFile
!= INVALID_HANDLE_VALUE
&& gptr() == egptr())
109 // Read in the next chunk of data, and set the pointers on success
111 if(!ReadFile(mFile
, mBuffer
.data(), mBuffer
.size(), &got
, NULL
))
113 setg(mBuffer
.data(), mBuffer
.data(), mBuffer
.data()+got
);
115 if(gptr() == egptr())
116 return traits_type::eof();
117 return traits_type::to_int_type(*gptr());
120 pos_type
seekoff(off_type offset
, std::ios_base::seekdir whence
, std::ios_base::openmode mode
) override
122 if(mFile
== INVALID_HANDLE_VALUE
|| (mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
123 return traits_type::eof();
128 case std::ios_base::beg
:
129 fpos
.QuadPart
= offset
;
130 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_BEGIN
))
131 return traits_type::eof();
134 case std::ios_base::cur
:
135 // If the offset remains in the current buffer range, just
136 // update the pointer.
137 if((offset
>= 0 && offset
< off_type(egptr()-gptr())) ||
138 (offset
< 0 && -offset
<= off_type(gptr()-eback())))
140 // Get the current file offset to report the correct read
143 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_CURRENT
))
144 return traits_type::eof();
145 setg(eback(), gptr()+offset
, egptr());
146 return fpos
.QuadPart
- off_type(egptr()-gptr());
148 // Need to offset for the file offset being at egptr() while
149 // the requested offset is relative to gptr().
150 offset
-= off_type(egptr()-gptr());
151 fpos
.QuadPart
= offset
;
152 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_CURRENT
))
153 return traits_type::eof();
156 case std::ios_base::end
:
157 fpos
.QuadPart
= offset
;
158 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_END
))
159 return traits_type::eof();
163 return traits_type::eof();
166 return fpos
.QuadPart
;
169 pos_type
seekpos(pos_type pos
, std::ios_base::openmode mode
) override
171 // Simplified version of seekoff
172 if(mFile
== INVALID_HANDLE_VALUE
|| (mode
&std::ios_base::out
) || !(mode
&std::ios_base::in
))
173 return traits_type::eof();
177 if(!SetFilePointerEx(mFile
, fpos
, &fpos
, FILE_BEGIN
))
178 return traits_type::eof();
181 return fpos
.QuadPart
;
185 bool open(const char *filename
)
187 alure::Vector
<wchar_t> wname
;
190 wnamelen
= MultiByteToWideChar(CP_UTF8
, 0, filename
, -1, NULL
, 0);
191 if(wnamelen
<= 0) return false;
193 wname
.resize(wnamelen
);
194 MultiByteToWideChar(CP_UTF8
, 0, filename
, -1, wname
.data(), wnamelen
);
196 mFile
= CreateFileW(wname
.data(), GENERIC_READ
, FILE_SHARE_READ
, NULL
,
197 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, nullptr);
198 if(mFile
== INVALID_HANDLE_VALUE
) return false;
202 bool is_open() const { return mFile
!= INVALID_HANDLE_VALUE
; }
204 StreamBuf() : mFile(INVALID_HANDLE_VALUE
)
206 ~StreamBuf() override
208 if(mFile
!= INVALID_HANDLE_VALUE
)
210 mFile
= INVALID_HANDLE_VALUE
;
214 // Inherit from std::istream to use our custom streambuf
215 class Stream final
: public std::istream
{
217 Stream(const char *filename
) : std::istream(new StreamBuf())
219 // Set the failbit if the file failed to open.
220 if(!(static_cast<StreamBuf
*>(rdbuf())->open(filename
)))
226 bool is_open() const { return static_cast<StreamBuf
*>(rdbuf())->is_open(); }
230 using DecoderEntryPair
= std::pair
<alure::String
,alure::UniquePtr
<alure::DecoderFactory
>>;
231 const DecoderEntryPair sDefaultDecoders
[] = {
232 { "_alure_int_wave", alure::MakeUnique
<alure::WaveDecoderFactory
>() },
234 #ifdef HAVE_VORBISFILE
235 { "_alure_int_vorbis", alure::MakeUnique
<alure::VorbisFileDecoderFactory
>() },
238 { "_alure_int_flac", alure::MakeUnique
<alure::FlacDecoderFactory
>() },
241 { "_alure_int_opus", alure::MakeUnique
<alure::OpusFileDecoderFactory
>() },
243 #ifdef HAVE_LIBSNDFILE
244 { "_alure_int_sndfile", alure::MakeUnique
<alure::SndFileDecoderFactory
>() },
247 { "_alure_int_mpg123", alure::MakeUnique
<alure::Mpg123DecoderFactory
>() },
250 alure::Vector
<DecoderEntryPair
> sDecoders
;
254 alure::DecoderOrExceptT
GetDecoder(alure::StringView name
, alure::UniquePtr
<std::istream
> &file
,
257 alure::DecoderOrExceptT ret
;
260 alure::DecoderFactory
*factory
= start
->second
.get();
261 auto decoder
= factory
->createDecoder(file
);
262 if(decoder
) return (ret
= std::move(decoder
));
264 if(!file
|| !(file
->clear(),file
->seekg(0)))
265 return (ret
= std::runtime_error("Failed to rewind "+name
+" for the next decoder factory"));
270 return (ret
= nullptr);
273 static alure::DecoderOrExceptT
GetDecoder(alure::StringView name
, alure::UniquePtr
<std::istream
> file
)
275 auto decoder
= GetDecoder(name
, file
, sDecoders
.begin(), sDecoders
.end());
276 if(std::holds_alternative
<std::runtime_error
>(decoder
)) return decoder
;
277 if(std::get
<alure::SharedPtr
<alure::Decoder
>>(decoder
)) return decoder
;
278 decoder
= GetDecoder(name
, file
, std::begin(sDefaultDecoders
), std::end(sDefaultDecoders
));
279 if(std::holds_alternative
<std::runtime_error
>(decoder
)) return decoder
;
280 if(std::get
<alure::SharedPtr
<alure::Decoder
>>(decoder
)) return decoder
;
281 return (decoder
= std::runtime_error("No decoder for "+name
));
284 class DefaultFileIOFactory final
: public alure::FileIOFactory
{
285 alure::UniquePtr
<std::istream
> openFile(const alure::String
&name
) override
288 auto file
= alure::MakeUnique
<Stream
>(name
.c_str());
290 auto file
= alure::MakeUnique
<std::ifstream
>(name
.c_str(), std::ios::binary
);
292 if(!file
->is_open()) file
= nullptr;
293 return std::move(file
);
296 DefaultFileIOFactory sDefaultFileFactory
;
298 alure::UniquePtr
<alure::FileIOFactory
> sFileFactory
;
305 Decoder::~Decoder() { }
306 DecoderFactory::~DecoderFactory() { }
308 void RegisterDecoder(StringView name
, UniquePtr
<DecoderFactory
> factory
)
310 auto iter
= std::lower_bound(sDecoders
.begin(), sDecoders
.end(), name
,
311 [](const DecoderEntryPair
&entry
, StringView rhs
) -> bool
312 { return entry
.first
< rhs
; }
314 if(iter
!= sDecoders
.end())
315 throw std::runtime_error("Decoder factory \""+name
+"\" already registered");
316 sDecoders
.insert(iter
, std::make_pair(String(name
), std::move(factory
)));
319 UniquePtr
<DecoderFactory
> UnregisterDecoder(StringView name
)
321 auto iter
= std::lower_bound(sDecoders
.begin(), sDecoders
.end(), name
,
322 [](const DecoderEntryPair
&entry
, StringView rhs
) -> bool
323 { return entry
.first
< rhs
; }
325 if(iter
!= sDecoders
.end())
327 UniquePtr
<DecoderFactory
> factory
= std::move(iter
->second
);
328 sDecoders
.erase(iter
);
335 FileIOFactory::~FileIOFactory() { }
337 UniquePtr
<FileIOFactory
> FileIOFactory::set(UniquePtr
<FileIOFactory
> factory
)
339 std::swap(sFileFactory
, factory
);
343 FileIOFactory
&FileIOFactory::get()
345 FileIOFactory
*factory
= sFileFactory
.get();
346 if(factory
) return *factory
;
347 return sDefaultFileFactory
;
351 // Default message handler methods are no-ops.
352 MessageHandler::~MessageHandler()
356 void MessageHandler::deviceDisconnected(Device
)
360 void MessageHandler::sourceStopped(Source
)
364 void MessageHandler::sourceForceStopped(Source
)
368 void MessageHandler::bufferLoading(StringView
, ChannelConfig
, SampleType
, ALuint
, ArrayView
<ALbyte
>)
372 String
MessageHandler::resourceNotFound(StringView
)
379 static inline void LoadALFunc(T
**func
, const char *name
)
380 { *func
= reinterpret_cast<T
*>(alGetProcAddress(name
)); }
382 static void LoadNothing(ContextImpl
*) { }
384 static void LoadEFX(ContextImpl
*ctx
)
386 LoadALFunc(&ctx
->alGenEffects
, "alGenEffects");
387 LoadALFunc(&ctx
->alDeleteEffects
, "alDeleteEffects");
388 LoadALFunc(&ctx
->alIsEffect
, "alIsEffect");
389 LoadALFunc(&ctx
->alEffecti
, "alEffecti");
390 LoadALFunc(&ctx
->alEffectiv
, "alEffectiv");
391 LoadALFunc(&ctx
->alEffectf
, "alEffectf");
392 LoadALFunc(&ctx
->alEffectfv
, "alEffectfv");
393 LoadALFunc(&ctx
->alGetEffecti
, "alGetEffecti");
394 LoadALFunc(&ctx
->alGetEffectiv
, "alGetEffectiv");
395 LoadALFunc(&ctx
->alGetEffectf
, "alGetEffectf");
396 LoadALFunc(&ctx
->alGetEffectfv
, "alGetEffectfv");
398 LoadALFunc(&ctx
->alGenFilters
, "alGenFilters");
399 LoadALFunc(&ctx
->alDeleteFilters
, "alDeleteFilters");
400 LoadALFunc(&ctx
->alIsFilter
, "alIsFilter");
401 LoadALFunc(&ctx
->alFilteri
, "alFilteri");
402 LoadALFunc(&ctx
->alFilteriv
, "alFilteriv");
403 LoadALFunc(&ctx
->alFilterf
, "alFilterf");
404 LoadALFunc(&ctx
->alFilterfv
, "alFilterfv");
405 LoadALFunc(&ctx
->alGetFilteri
, "alGetFilteri");
406 LoadALFunc(&ctx
->alGetFilteriv
, "alGetFilteriv");
407 LoadALFunc(&ctx
->alGetFilterf
, "alGetFilterf");
408 LoadALFunc(&ctx
->alGetFilterfv
, "alGetFilterfv");
410 LoadALFunc(&ctx
->alGenAuxiliaryEffectSlots
, "alGenAuxiliaryEffectSlots");
411 LoadALFunc(&ctx
->alDeleteAuxiliaryEffectSlots
, "alDeleteAuxiliaryEffectSlots");
412 LoadALFunc(&ctx
->alIsAuxiliaryEffectSlot
, "alIsAuxiliaryEffectSlot");
413 LoadALFunc(&ctx
->alAuxiliaryEffectSloti
, "alAuxiliaryEffectSloti");
414 LoadALFunc(&ctx
->alAuxiliaryEffectSlotiv
, "alAuxiliaryEffectSlotiv");
415 LoadALFunc(&ctx
->alAuxiliaryEffectSlotf
, "alAuxiliaryEffectSlotf");
416 LoadALFunc(&ctx
->alAuxiliaryEffectSlotfv
, "alAuxiliaryEffectSlotfv");
417 LoadALFunc(&ctx
->alGetAuxiliaryEffectSloti
, "alGetAuxiliaryEffectSloti");
418 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotiv
, "alGetAuxiliaryEffectSlotiv");
419 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotf
, "alGetAuxiliaryEffectSlotf");
420 LoadALFunc(&ctx
->alGetAuxiliaryEffectSlotfv
, "alGetAuxiliaryEffectSlotfv");
423 static void LoadSourceResampler(ContextImpl
*ctx
)
425 LoadALFunc(&ctx
->alGetStringiSOFT
, "alGetStringiSOFT");
428 static void LoadSourceLatency(ContextImpl
*ctx
)
430 LoadALFunc(&ctx
->alGetSourcei64vSOFT
, "alGetSourcei64vSOFT");
431 LoadALFunc(&ctx
->alGetSourcedvSOFT
, "alGetSourcedvSOFT");
434 static const struct {
437 void (&loader
)(ContextImpl
*);
438 } ALExtensionList
[] = {
439 { AL::EXT_EFX
, "ALC_EXT_EFX", LoadEFX
},
441 { AL::EXT_FLOAT32
, "AL_EXT_FLOAT32", LoadNothing
},
442 { AL::EXT_MCFORMATS
, "AL_EXT_MCFORMATS", LoadNothing
},
443 { AL::EXT_BFORMAT
, "AL_EXT_BFORMAT", LoadNothing
},
445 { AL::EXT_MULAW
, "AL_EXT_MULAW", LoadNothing
},
446 { AL::EXT_MULAW_MCFORMATS
, "AL_EXT_MULAW_MCFORMATS", LoadNothing
},
447 { AL::EXT_MULAW_BFORMAT
, "AL_EXT_MULAW_BFORMAT", LoadNothing
},
449 { AL::SOFT_loop_points
, "AL_SOFT_loop_points", LoadNothing
},
450 { AL::SOFT_source_latency
, "AL_SOFT_source_latency", LoadSourceLatency
},
451 { AL::SOFT_source_resampler
, "AL_SOFT_source_resampler", LoadSourceResampler
},
452 { AL::SOFT_source_spatialize
, "AL_SOFT_source_spatialize", LoadNothing
},
454 { AL::EXT_disconnect
, "ALC_EXT_disconnect", LoadNothing
},
456 { AL::EXT_SOURCE_RADIUS
, "AL_EXT_SOURCE_RADIUS", LoadNothing
},
457 { AL::EXT_STEREO_ANGLES
, "AL_EXT_STEREO_ANGLES", LoadNothing
},
461 ContextImpl
*ContextImpl::sCurrentCtx
= nullptr;
462 thread_local ContextImpl
*ContextImpl::sThreadCurrentCtx
= nullptr;
464 std::atomic
<uint64_t> ContextImpl::sContextSetCount
{0};
466 void ContextImpl::MakeCurrent(ContextImpl
*context
)
468 std::unique_lock
<std::mutex
> ctxlock(mGlobalCtxMutex
);
470 if(alcMakeContextCurrent(context
? context
->getALCcontext() : nullptr) == ALC_FALSE
)
471 throw std::runtime_error("Call to alcMakeContextCurrent failed");
475 std::call_once(context
->mSetExts
, std::mem_fn(&ContextImpl::setupExts
), context
);
477 std::swap(sCurrentCtx
, context
);
478 if(context
) context
->decRef();
480 if(sThreadCurrentCtx
)
481 sThreadCurrentCtx
->decRef();
482 sThreadCurrentCtx
= nullptr;
483 sContextSetCount
.fetch_add(1, std::memory_order_release
);
485 if((context
= sCurrentCtx
) != nullptr)
488 context
->mWakeThread
.notify_all();
492 void ContextImpl::MakeThreadCurrent(ContextImpl
*context
)
494 if(!DeviceManagerImpl::SetThreadContext
)
495 throw std::runtime_error("Thread-local contexts unsupported");
496 if(DeviceManagerImpl::SetThreadContext(context
? context
->getALCcontext() : nullptr) == ALC_FALSE
)
497 throw std::runtime_error("Call to alcSetThreadContext failed");
501 std::call_once(context
->mSetExts
, std::mem_fn(&ContextImpl::setupExts
), context
);
503 if(sThreadCurrentCtx
)
504 sThreadCurrentCtx
->decRef();
505 sThreadCurrentCtx
= context
;
506 sContextSetCount
.fetch_add(1, std::memory_order_release
);
509 void ContextImpl::setupExts()
511 ALCdevice
*device
= mDevice
->getALCdevice();
513 for(const auto &entry
: ALExtensionList
)
515 if((strncmp(entry
.name
, "ALC", 3) == 0) ? alcIsExtensionPresent(device
, entry
.name
) :
516 alIsExtensionPresent(entry
.name
))
518 mHasExt
.set(static_cast<size_t>(entry
.extension
));
525 void ContextImpl::backgroundProc()
527 if(DeviceManagerImpl::SetThreadContext
&& mDevice
->hasExtension(ALC::EXT_thread_local_context
))
528 DeviceManagerImpl::SetThreadContext(getALCcontext());
530 std::chrono::steady_clock::time_point basetime
= std::chrono::steady_clock::now();
531 std::chrono::milliseconds
waketime(0);
532 std::unique_lock
<std::mutex
> ctxlock(mGlobalCtxMutex
);
533 while(!mQuitThread
.load(std::memory_order_acquire
))
536 std::lock_guard
<std::mutex
> srclock(mSourceStreamMutex
);
537 mStreamingSources
.erase(
538 std::remove_if(mStreamingSources
.begin(), mStreamingSources
.end(),
539 [](SourceImpl
*source
) -> bool
540 { return !source
->updateAsync(); }
541 ), mStreamingSources
.end()
545 // Only do one pending buffer at a time. In case there's several large
546 // buffers to load, we still need to process streaming sources so they
548 PendingBuffer
*lastpb
= mPendingCurrent
.load(std::memory_order_acquire
);
549 if(PendingBuffer
*pb
= lastpb
->mNext
.load(std::memory_order_relaxed
))
551 pb
->mBuffer
->load(pb
->mFrames
, pb
->mFormat
, std::move(pb
->mDecoder
), this);
552 pb
->mPromise
.set_value(Buffer(pb
->mBuffer
));
553 Promise
<Buffer
>().swap(pb
->mPromise
);
554 mPendingCurrent
.store(pb
, std::memory_order_release
);
558 std::unique_lock
<std::mutex
> wakelock(mWakeMutex
);
559 if(!mQuitThread
.load(std::memory_order_acquire
) && lastpb
->mNext
.load(std::memory_order_acquire
) == nullptr)
563 std::chrono::milliseconds interval
= mWakeInterval
.load(std::memory_order_relaxed
);
564 if(interval
.count() == 0)
565 mWakeThread
.wait(wakelock
);
568 auto now
= std::chrono::steady_clock::now() - basetime
;
571 auto mult
= (now
-waketime
+ interval
-std::chrono::milliseconds(1)) / interval
;
572 waketime
+= interval
* mult
;
574 mWakeThread
.wait_until(wakelock
, waketime
+ basetime
);
579 while(!mQuitThread
.load(std::memory_order_acquire
) &&
580 alcGetCurrentContext() != getALCcontext())
581 mWakeThread
.wait(ctxlock
);
586 if(DeviceManagerImpl::SetThreadContext
)
587 DeviceManagerImpl::SetThreadContext(nullptr);
591 ContextImpl::ContextImpl(ALCcontext
*context
, DeviceImpl
*device
)
592 : mContextSetCounter(std::numeric_limits
<uint64_t>::max()),
593 mListener(this), mContext(context
), mDevice(device
),
594 mWakeInterval(std::chrono::milliseconds::zero()), mQuitThread(false),
595 mRefs(0), mIsConnected(true), mIsBatching(false),
596 alGetSourcei64vSOFT(0), alGetSourcedvSOFT(0),
597 alGenEffects(0), alDeleteEffects(0), alIsEffect(0),
598 alEffecti(0), alEffectiv(0), alEffectf(0), alEffectfv(0),
599 alGetEffecti(0), alGetEffectiv(0), alGetEffectf(0), alGetEffectfv(0),
600 alGenFilters(0), alDeleteFilters(0), alIsFilter(0),
601 alFilteri(0), alFilteriv(0), alFilterf(0), alFilterfv(0),
602 alGetFilteri(0), alGetFilteriv(0), alGetFilterf(0), alGetFilterfv(0),
603 alGenAuxiliaryEffectSlots(0), alDeleteAuxiliaryEffectSlots(0), alIsAuxiliaryEffectSlot(0),
604 alAuxiliaryEffectSloti(0), alAuxiliaryEffectSlotiv(0), alAuxiliaryEffectSlotf(0), alAuxiliaryEffectSlotfv(0),
605 alGetAuxiliaryEffectSloti(0), alGetAuxiliaryEffectSlotiv(0), alGetAuxiliaryEffectSlotf(0), alGetAuxiliaryEffectSlotfv(0)
608 mPendingHead
= new PendingBuffer
;
609 mPendingCurrent
.store(mPendingHead
, std::memory_order_relaxed
);
610 mPendingTail
= mPendingHead
;
613 ContextImpl::~ContextImpl()
615 PendingBuffer
*pb
= mPendingTail
;
618 PendingBuffer
*next
= pb
->mNext
.load(std::memory_order_relaxed
);
622 mPendingCurrent
.store(nullptr, std::memory_order_relaxed
);
623 mPendingHead
= nullptr;
624 mPendingTail
= nullptr;
628 void ContextImpl::destroy()
631 throw std::runtime_error("Context is in use");
632 if(!mBuffers
.empty())
633 throw std::runtime_error("Trying to destroy a context with buffers");
635 if(mThread
.joinable())
637 std::unique_lock
<std::mutex
> lock(mWakeMutex
);
638 mQuitThread
.store(true, std::memory_order_release
);
640 mWakeThread
.notify_all();
644 alcDestroyContext(mContext
);
647 mDevice
->removeContext(this);
651 void ContextImpl::startBatch()
653 alcSuspendContext(mContext
);
657 void ContextImpl::endBatch()
659 alcProcessContext(mContext
);
664 SharedPtr
<MessageHandler
> ContextImpl::setMessageHandler(SharedPtr
<MessageHandler
>&& handler
)
666 std::lock_guard
<std::mutex
> lock(mGlobalCtxMutex
);
667 mMessage
.swap(handler
);
672 void ContextImpl::setAsyncWakeInterval(std::chrono::milliseconds interval
)
674 if(interval
.count() < 0 || interval
> std::chrono::seconds(1))
675 throw std::runtime_error("Async wake interval out of range");
676 mWakeInterval
.store(interval
);
677 mWakeMutex
.lock(); mWakeMutex
.unlock();
678 mWakeThread
.notify_all();
682 DecoderOrExceptT
ContextImpl::findDecoder(StringView name
)
684 DecoderOrExceptT ret
;
686 String oldname
= String(name
);
687 auto file
= FileIOFactory::get().openFile(oldname
);
688 if(file
) return (ret
= GetDecoder(name
, std::move(file
)));
690 // Resource not found. Try to find a substitute.
691 if(!mMessage
.get()) return (ret
= std::runtime_error("Failed to open "+oldname
));
693 String
newname(mMessage
->resourceNotFound(oldname
));
695 return (ret
= std::runtime_error("Failed to open "+oldname
));
696 file
= FileIOFactory::get().openFile(newname
);
697 oldname
= std::move(newname
);
700 return (ret
= GetDecoder(oldname
, std::move(file
)));
703 SharedPtr
<Decoder
> ContextImpl::createDecoder(StringView name
)
706 DecoderOrExceptT dec
= findDecoder(name
);
707 if(SharedPtr
<Decoder
> *decoder
= std::get_if
<SharedPtr
<Decoder
>>(&dec
))
709 throw std::get
<std::runtime_error
>(dec
);
713 bool ContextImpl::isSupported(ChannelConfig channels
, SampleType type
) const
716 return GetFormat(channels
, type
) != AL_NONE
;
720 ArrayView
<String
> ContextImpl::getAvailableResamplers()
723 if(mResamplers
.empty() && hasExtension(AL::SOFT_source_resampler
))
725 ALint num_resamplers
= alGetInteger(AL_NUM_RESAMPLERS_SOFT
);
726 mResamplers
.reserve(num_resamplers
);
727 for(int i
= 0;i
< num_resamplers
;i
++)
728 mResamplers
.emplace_back(alGetStringiSOFT(AL_RESAMPLER_NAME_SOFT
, i
));
729 if(mResamplers
.empty())
730 mResamplers
.emplace_back();
735 ALsizei
ContextImpl::getDefaultResamplerIndex() const
738 if(!hasExtension(AL::SOFT_source_resampler
))
740 return alGetInteger(AL_DEFAULT_RESAMPLER_SOFT
);
744 BufferOrExceptT
ContextImpl::doCreateBuffer(StringView name
, Vector
<UniquePtr
<BufferImpl
>>::iterator iter
, SharedPtr
<Decoder
> decoder
)
746 BufferOrExceptT retval
;
747 ALuint srate
= decoder
->getFrequency();
748 ChannelConfig chans
= decoder
->getChannelConfig();
749 SampleType type
= decoder
->getSampleType();
750 ALuint frames
= decoder
->getLength();
752 Vector
<ALbyte
> data(FramesToBytes(frames
, chans
, type
));
753 frames
= decoder
->read(data
.data(), frames
);
754 if(!frames
) return (retval
= std::runtime_error("No samples for buffer"));
755 data
.resize(FramesToBytes(frames
, chans
, type
));
757 std::pair
<uint64_t,uint64_t> loop_pts
= decoder
->getLoopPoints();
758 if(loop_pts
.first
>= loop_pts
.second
)
759 loop_pts
= std::make_pair(0, frames
);
762 loop_pts
.second
= std::min
<uint64_t>(loop_pts
.second
, frames
);
763 loop_pts
.first
= std::min
<uint64_t>(loop_pts
.first
, loop_pts
.second
-1);
766 // Get the format before calling the bufferLoading message handler, to
767 // ensure it's something OpenAL can handle.
768 ALenum format
= GetFormat(chans
, type
);
769 if(format
== AL_NONE
)
771 std::stringstream sstr
;
772 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
773 return (retval
= std::runtime_error(sstr
.str()));
777 mMessage
->bufferLoading(name
, chans
, type
, srate
, data
);
781 alGenBuffers(1, &bid
);
782 alBufferData(bid
, format
, data
.data(), data
.size(), srate
);
783 if(hasExtension(AL::SOFT_loop_points
))
785 ALint pts
[2]{(ALint
)loop_pts
.first
, (ALint
)loop_pts
.second
};
786 alBufferiv(bid
, AL_LOOP_POINTS_SOFT
, pts
);
788 if(alGetError() != AL_NO_ERROR
)
790 alDeleteBuffers(1, &bid
);
791 return (retval
= std::runtime_error("Failed to buffer data"));
794 return (retval
= mBuffers
.insert(iter
,
795 MakeUnique
<BufferImpl
>(this, bid
, srate
, chans
, type
, name
)
799 BufferOrExceptT
ContextImpl::doCreateBufferAsync(StringView name
, Vector
<UniquePtr
<BufferImpl
>>::iterator iter
, SharedPtr
<Decoder
> decoder
, Promise
<Buffer
> promise
)
801 BufferOrExceptT retval
;
802 ALuint srate
= decoder
->getFrequency();
803 ChannelConfig chans
= decoder
->getChannelConfig();
804 SampleType type
= decoder
->getSampleType();
805 ALuint frames
= decoder
->getLength();
806 if(!frames
) return (retval
= std::runtime_error("No samples for buffer"));
808 ALenum format
= GetFormat(chans
, type
);
809 if(format
== AL_NONE
)
811 std::stringstream sstr
;
812 sstr
<< "Format not supported ("<<GetSampleTypeName(type
)<<", "<<GetChannelConfigName(chans
)<<")";
813 return (retval
= std::runtime_error(sstr
.str()));
818 alGenBuffers(1, &bid
);
819 if(alGetError() != AL_NO_ERROR
)
820 return (retval
= std::runtime_error("Failed to create buffer"));
822 auto buffer
= MakeUnique
<BufferImpl
>(this, bid
, srate
, chans
, type
, name
);
824 if(mThread
.get_id() == std::thread::id())
825 mThread
= std::thread(std::mem_fn(&ContextImpl::backgroundProc
), this);
827 PendingBuffer
*pb
= nullptr;
828 if(mPendingTail
== mPendingCurrent
.load(std::memory_order_acquire
))
829 pb
= new PendingBuffer
{buffer
.get(), decoder
, format
, frames
, std::move(promise
)};
833 pb
->mBuffer
= buffer
.get();
834 pb
->mDecoder
= decoder
;
835 pb
->mFormat
= format
;
836 pb
->mFrames
= frames
;
837 pb
->mPromise
= std::move(promise
);
838 mPendingTail
= pb
->mNext
.exchange(nullptr, std::memory_order_relaxed
);
841 mPendingHead
->mNext
.store(pb
, std::memory_order_release
);
844 return (retval
= mBuffers
.insert(iter
, std::move(buffer
))->get());
847 Buffer
ContextImpl::getBuffer(StringView name
)
851 auto hasher
= std::hash
<StringView
>();
852 if(UNLIKELY(!mFutureBuffers
.empty()))
856 // If the buffer is already pending for the future, wait for it
857 auto iter
= std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
858 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
859 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
861 if(iter
!= mFutureBuffers
.end() && iter
->mBuffer
->getName() == name
)
863 buffer
= iter
->mFuture
.get();
864 mFutureBuffers
.erase(iter
);
867 // Clear out any completed futures.
868 mFutureBuffers
.erase(
869 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
870 [](const PendingFuture
&entry
) -> bool
871 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
872 ), mFutureBuffers
.end()
875 // If we got the buffer, return it. Otherwise, go load it normally.
876 if(buffer
) return buffer
;
879 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
880 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
881 { return hasher(lhs
->getName()) < rhs
; }
883 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
884 return Buffer(iter
->get());
886 BufferOrExceptT ret
= doCreateBuffer(name
, iter
, createDecoder(name
));
887 Buffer
*buffer
= std::get_if
<Buffer
>(&ret
);
888 if(UNLIKELY(!buffer
))
889 throw std::get
<std::runtime_error
>(ret
);
893 SharedFuture
<Buffer
> ContextImpl::getBufferAsync(StringView name
)
895 SharedFuture
<Buffer
> future
;
898 auto hasher
= std::hash
<StringView
>();
899 if(UNLIKELY(!mFutureBuffers
.empty()))
901 // Check if the future that's being created already exists
902 auto iter
= std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
903 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
904 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
906 if(iter
!= mFutureBuffers
.end() && iter
->mBuffer
->getName() == name
)
908 future
= iter
->mFuture
;
909 if(future
.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready
)
910 mFutureBuffers
.erase(iter
);
914 // Clear out any fulfilled futures.
915 mFutureBuffers
.erase(
916 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
917 [](const PendingFuture
&entry
) -> bool
918 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
919 ), mFutureBuffers
.end()
923 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
924 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
925 { return hasher(lhs
->getName()) < rhs
; }
927 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
929 // User asked to create a future buffer that's already loaded. Just
930 // construct a promise, fulfill the promise immediately, then return a
931 // shared future that's already set.
932 Promise
<Buffer
> promise
;
933 promise
.set_value(Buffer(iter
->get()));
934 future
= promise
.get_future().share();
938 Promise
<Buffer
> promise
;
939 future
= promise
.get_future().share();
941 BufferOrExceptT ret
= doCreateBufferAsync(name
, iter
, createDecoder(name
), std::move(promise
));
942 Buffer
*buffer
= std::get_if
<Buffer
>(&ret
);
943 if(UNLIKELY(!buffer
))
944 throw std::get
<std::runtime_error
>(ret
);
945 mWakeMutex
.lock(); mWakeMutex
.unlock();
946 mWakeThread
.notify_all();
948 mFutureBuffers
.insert(
949 std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
950 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
951 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
952 ), { buffer
->getHandle(), future
}
958 void ContextImpl::precacheBuffersAsync(ArrayView
<StringView
> names
)
962 if(UNLIKELY(!mFutureBuffers
.empty()))
964 // Clear out any fulfilled futures.
965 mFutureBuffers
.erase(
966 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
967 [](const PendingFuture
&entry
) -> bool
968 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
969 ), mFutureBuffers
.end()
973 auto hasher
= std::hash
<StringView
>();
974 for(const StringView name
: names
)
976 // Check if the buffer that's being created already exists
977 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
978 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
979 { return hasher(lhs
->getName()) < rhs
; }
981 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
984 DecoderOrExceptT dec
= findDecoder(name
);
985 SharedPtr
<Decoder
> *decoder
= std::get_if
<SharedPtr
<Decoder
>>(&dec
);
986 if(!decoder
) continue;
988 Promise
<Buffer
> promise
;
989 SharedFuture
<Buffer
> future
= promise
.get_future().share();
991 BufferOrExceptT buf
= doCreateBufferAsync(name
, iter
, std::move(*decoder
),
993 Buffer
*buffer
= std::get_if
<Buffer
>(&buf
);
994 if(UNLIKELY(!buffer
)) continue;
996 mFutureBuffers
.insert(
997 std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
998 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
999 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
1000 ), { buffer
->getHandle(), future
}
1003 mWakeMutex
.lock(); mWakeMutex
.unlock();
1004 mWakeThread
.notify_all();
1007 Buffer
ContextImpl::createBufferFrom(StringView name
, SharedPtr
<Decoder
>&& decoder
)
1011 auto hasher
= std::hash
<StringView
>();
1012 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
1013 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
1014 { return hasher(lhs
->getName()) < rhs
; }
1016 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
1017 throw std::runtime_error("Buffer \""+name
+"\" already exists");
1019 BufferOrExceptT ret
= doCreateBuffer(name
, iter
, std::move(decoder
));
1020 Buffer
*buffer
= std::get_if
<Buffer
>(&ret
);
1021 if(UNLIKELY(!buffer
))
1022 throw std::get
<std::runtime_error
>(ret
);
1026 SharedFuture
<Buffer
> ContextImpl::createBufferAsyncFrom(StringView name
, SharedPtr
<Decoder
>&& decoder
)
1028 SharedFuture
<Buffer
> future
;
1031 if(UNLIKELY(!mFutureBuffers
.empty()))
1033 // Clear out any fulfilled futures.
1034 mFutureBuffers
.erase(
1035 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
1036 [](const PendingFuture
&entry
) -> bool
1037 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
1038 ), mFutureBuffers
.end()
1042 auto hasher
= std::hash
<StringView
>();
1043 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
1044 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
1045 { return hasher(lhs
->getName()) < rhs
; }
1047 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
1048 throw std::runtime_error("Buffer \""+name
+"\" already exists");
1050 Promise
<Buffer
> promise
;
1051 future
= promise
.get_future().share();
1053 BufferOrExceptT ret
= doCreateBufferAsync(name
, iter
, std::move(decoder
), std::move(promise
));
1054 Buffer
*buffer
= std::get_if
<Buffer
>(&ret
);
1055 if(UNLIKELY(!buffer
))
1056 throw std::get
<std::runtime_error
>(ret
);
1057 mWakeMutex
.lock(); mWakeMutex
.unlock();
1058 mWakeThread
.notify_all();
1060 mFutureBuffers
.insert(
1061 std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
1062 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
1063 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
1064 ), { buffer
->getHandle(), future
}
1071 Buffer
ContextImpl::findBuffer(StringView name
)
1076 auto hasher
= std::hash
<StringView
>();
1077 if(UNLIKELY(!mFutureBuffers
.empty()))
1079 // If the buffer is already pending for the future, wait for it
1080 auto iter
= std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
1081 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
1082 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
1084 if(iter
!= mFutureBuffers
.end() && iter
->mBuffer
->getName() == name
)
1086 buffer
= iter
->mFuture
.get();
1087 mFutureBuffers
.erase(iter
);
1090 // Clear out any completed futures.
1091 mFutureBuffers
.erase(
1092 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
1093 [](const PendingFuture
&entry
) -> bool
1094 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
1095 ), mFutureBuffers
.end()
1101 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
1102 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
1103 { return hasher(lhs
->getName()) < rhs
; }
1105 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
1106 buffer
= Buffer(iter
->get());
1111 SharedFuture
<Buffer
> ContextImpl::findBufferAsync(StringView name
)
1113 SharedFuture
<Buffer
> future
;
1116 auto hasher
= std::hash
<StringView
>();
1117 if(UNLIKELY(!mFutureBuffers
.empty()))
1119 // Check if the future that's being created already exists
1120 auto iter
= std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
1121 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
1122 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
1124 if(iter
!= mFutureBuffers
.end() && iter
->mBuffer
->getName() == name
)
1126 future
= iter
->mFuture
;
1127 if(future
.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready
)
1128 mFutureBuffers
.erase(iter
);
1132 // Clear out any fulfilled futures.
1133 mFutureBuffers
.erase(
1134 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
1135 [](const PendingFuture
&entry
) -> bool
1136 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
1137 ), mFutureBuffers
.end()
1141 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
1142 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
1143 { return hasher(lhs
->getName()) < rhs
; }
1145 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
1147 // User asked to create a future buffer that's already loaded. Just
1148 // construct a promise, fulfill the promise immediately, then return a
1149 // shared future that's already set.
1150 Promise
<Buffer
> promise
;
1151 promise
.set_value(Buffer(iter
->get()));
1152 future
= promise
.get_future().share();
1158 void ContextImpl::removeBuffer(StringView name
)
1162 auto hasher
= std::hash
<StringView
>();
1163 if(UNLIKELY(!mFutureBuffers
.empty()))
1165 // If the buffer is already pending for the future, wait for it to
1166 // finish before continuing.
1167 auto iter
= std::lower_bound(mFutureBuffers
.begin(), mFutureBuffers
.end(), hasher(name
),
1168 [hasher
](const PendingFuture
&lhs
, size_t rhs
) -> bool
1169 { return hasher(lhs
.mBuffer
->getName()) < rhs
; }
1171 if(iter
!= mFutureBuffers
.end() && iter
->mBuffer
->getName() == name
)
1173 iter
->mFuture
.wait();
1174 mFutureBuffers
.erase(iter
);
1177 // Clear out any completed futures.
1178 mFutureBuffers
.erase(
1179 std::remove_if(mFutureBuffers
.begin(), mFutureBuffers
.end(),
1180 [](const PendingFuture
&entry
) -> bool
1181 { return entry
.mFuture
.wait_for(std::chrono::milliseconds(0)) == std::future_status::ready
; }
1182 ), mFutureBuffers
.end()
1186 auto iter
= std::lower_bound(mBuffers
.begin(), mBuffers
.end(), hasher(name
),
1187 [hasher
](const UniquePtr
<BufferImpl
> &lhs
, size_t rhs
) -> bool
1188 { return hasher(lhs
->getName()) < rhs
; }
1190 if(iter
!= mBuffers
.end() && (*iter
)->getName() == name
)
1192 // Remove pending sources whose future was waiting for this buffer.
1193 mPendingSources
.erase(
1194 std::remove_if(mPendingSources
.begin(), mPendingSources
.end(),
1195 [iter
](PendingSource
&entry
) -> bool
1197 return (entry
.mFuture
.wait_for(std::chrono::milliseconds::zero()) == std::future_status::ready
&&
1198 entry
.mFuture
.get().getHandle() == iter
->get());
1200 ), mPendingSources
.end()
1203 mBuffers
.erase(iter
);
1208 ALuint
ContextImpl::getSourceId(ALuint maxprio
)
1211 if(mSourceIds
.empty())
1214 alGenSources(1, &id
);
1215 if(alGetError() == AL_NO_ERROR
)
1218 SourceImpl
*lowest
= nullptr;
1219 for(SourceBufferUpdateEntry
&entry
: mPlaySources
)
1221 if(!lowest
|| entry
.mSource
->getPriority() < lowest
->getPriority())
1222 lowest
= entry
.mSource
;
1224 for(SourceStreamUpdateEntry
&entry
: mStreamSources
)
1226 if(!lowest
|| entry
.mSource
->getPriority() < lowest
->getPriority())
1227 lowest
= entry
.mSource
;
1229 if(lowest
&& lowest
->getPriority() < maxprio
)
1233 mMessage
->sourceForceStopped(lowest
);
1236 if(mSourceIds
.empty())
1237 throw std::runtime_error("No available sources");
1239 id
= mSourceIds
.top();
1245 Source
ContextImpl::createSource()
1250 if(!mFreeSources
.empty())
1252 source
= mFreeSources
.back();
1253 mFreeSources
.pop_back();
1257 mAllSources
.emplace_back(this);
1258 source
= &mAllSources
.back();
1260 return Source(source
);
1264 void ContextImpl::addPendingSource(SourceImpl
*source
, SharedFuture
<Buffer
> future
)
1266 auto iter
= std::lower_bound(mPendingSources
.begin(), mPendingSources
.end(), source
,
1267 [](const PendingSource
&lhs
, SourceImpl
*rhs
) -> bool
1268 { return lhs
.mSource
< rhs
; }
1270 if(iter
== mPendingSources
.end() || iter
->mSource
!= source
)
1271 mPendingSources
.insert(iter
, {source
, std::move(future
)});
1274 void ContextImpl::removePendingSource(SourceImpl
*source
)
1276 auto iter
= std::lower_bound(mPendingSources
.begin(), mPendingSources
.end(), source
,
1277 [](const PendingSource
&lhs
, SourceImpl
*rhs
) -> bool
1278 { return lhs
.mSource
< rhs
; }
1280 if(iter
!= mPendingSources
.end() && iter
->mSource
== source
)
1281 mPendingSources
.erase(iter
);
1284 bool ContextImpl::isPendingSource(const SourceImpl
*source
) const
1286 auto iter
= std::lower_bound(mPendingSources
.begin(), mPendingSources
.end(), source
,
1287 [](const PendingSource
&lhs
, const SourceImpl
*rhs
) -> bool
1288 { return lhs
.mSource
< rhs
; }
1290 return (iter
!= mPendingSources
.end() && iter
->mSource
== source
);
1293 void ContextImpl::addFadingSource(SourceImpl
*source
)
1295 auto iter
= std::lower_bound(mFadingSources
.begin(), mFadingSources
.end(), source
,
1296 [](SourceImpl
*lhs
, SourceImpl
*rhs
) -> bool
1297 { return lhs
< rhs
; }
1299 if(iter
== mFadingSources
.end() || *iter
!= source
)
1300 mFadingSources
.insert(iter
, source
);
1303 void ContextImpl::removeFadingSource(SourceImpl
*source
)
1305 auto iter
= std::lower_bound(mFadingSources
.begin(), mFadingSources
.end(), source
,
1306 [](SourceImpl
*lhs
, SourceImpl
*rhs
) -> bool
1307 { return lhs
< rhs
; }
1309 if(iter
!= mFadingSources
.end() && *iter
== source
)
1310 mFadingSources
.erase(iter
);
1313 void ContextImpl::addPlayingSource(SourceImpl
*source
, ALuint id
)
1315 auto iter
= std::lower_bound(mPlaySources
.begin(), mPlaySources
.end(), source
,
1316 [](const SourceBufferUpdateEntry
&lhs
, SourceImpl
*rhs
) -> bool
1317 { return lhs
.mSource
< rhs
; }
1319 if(iter
== mPlaySources
.end() || iter
->mSource
!= source
)
1320 mPlaySources
.insert(iter
, {source
,id
});
1323 void ContextImpl::addPlayingSource(SourceImpl
*source
)
1325 auto iter
= std::lower_bound(mStreamSources
.begin(), mStreamSources
.end(), source
,
1326 [](const SourceStreamUpdateEntry
&lhs
, SourceImpl
*rhs
) -> bool
1327 { return lhs
.mSource
< rhs
; }
1329 if(iter
== mStreamSources
.end() || iter
->mSource
!= source
)
1330 mStreamSources
.insert(iter
, {source
});
1333 void ContextImpl::removePlayingSource(SourceImpl
*source
)
1335 auto iter0
= std::lower_bound(mPlaySources
.begin(), mPlaySources
.end(), source
,
1336 [](const SourceBufferUpdateEntry
&lhs
, SourceImpl
*rhs
) -> bool
1337 { return lhs
.mSource
< rhs
; }
1339 if(iter0
!= mPlaySources
.end() && iter0
->mSource
== source
)
1340 mPlaySources
.erase(iter0
);
1343 auto iter1
= std::lower_bound(mStreamSources
.begin(), mStreamSources
.end(), source
,
1344 [](const SourceStreamUpdateEntry
&lhs
, SourceImpl
*rhs
) -> bool
1345 { return lhs
.mSource
< rhs
; }
1347 if(iter1
!= mStreamSources
.end() && iter1
->mSource
== source
)
1348 mStreamSources
.erase(iter1
);
1353 void ContextImpl::addStream(SourceImpl
*source
)
1355 std::lock_guard
<std::mutex
> lock(mSourceStreamMutex
);
1356 if(mThread
.get_id() == std::thread::id())
1357 mThread
= std::thread(std::mem_fn(&ContextImpl::backgroundProc
), this);
1358 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
1359 if(iter
== mStreamingSources
.end() || *iter
!= source
)
1360 mStreamingSources
.insert(iter
, source
);
1363 void ContextImpl::removeStream(SourceImpl
*source
)
1365 std::lock_guard
<std::mutex
> lock(mSourceStreamMutex
);
1366 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
1367 if(iter
!= mStreamingSources
.end() && *iter
== source
)
1368 mStreamingSources
.erase(iter
);
1371 void ContextImpl::removeStreamNoLock(SourceImpl
*source
)
1373 auto iter
= std::lower_bound(mStreamingSources
.begin(), mStreamingSources
.end(), source
);
1374 if(iter
!= mStreamingSources
.end() && *iter
== source
)
1375 mStreamingSources
.erase(iter
);
1379 AuxiliaryEffectSlot
ContextImpl::createAuxiliaryEffectSlot()
1381 if(!hasExtension(AL::EXT_EFX
) || !alGenAuxiliaryEffectSlots
)
1382 throw std::runtime_error("AuxiliaryEffectSlots not supported");
1387 alGenAuxiliaryEffectSlots(1, &id
);
1388 if(alGetError() != AL_NO_ERROR
)
1389 throw std::runtime_error("Failed to create AuxiliaryEffectSlot");
1391 return AuxiliaryEffectSlot(new AuxiliaryEffectSlotImpl(this, id
));
1394 alDeleteAuxiliaryEffectSlots(1, &id
);
1400 Effect
ContextImpl::createEffect()
1402 if(!hasExtension(AL::EXT_EFX
))
1403 throw std::runtime_error("Effects not supported");
1408 alGenEffects(1, &id
);
1409 if(alGetError() != AL_NO_ERROR
)
1410 throw std::runtime_error("Failed to create Effect");
1412 return Effect(new EffectImpl(this, id
));
1415 alDeleteEffects(1, &id
);
1421 SourceGroup
ContextImpl::createSourceGroup(StringView name
)
1423 auto hasher
= std::hash
<StringView
>();
1424 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), hasher(name
),
1425 [hasher
](const UniquePtr
<SourceGroupImpl
> &lhs
, size_t rhs
) -> bool
1426 { return hasher(lhs
->getName()) < rhs
; }
1428 if(iter
!= mSourceGroups
.end() && (*iter
)->getName() == name
)
1429 throw std::runtime_error("Duplicate source group name");
1430 iter
= mSourceGroups
.insert(iter
, MakeUnique
<SourceGroupImpl
>(this, name
));
1431 return SourceGroup(iter
->get());
1434 SourceGroup
ContextImpl::getSourceGroup(StringView name
)
1436 auto hasher
= std::hash
<StringView
>();
1437 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), hasher(name
),
1438 [hasher
](const UniquePtr
<SourceGroupImpl
> &lhs
, size_t rhs
) -> bool
1439 { return hasher(lhs
->getName()) < rhs
; }
1441 if(iter
== mSourceGroups
.end() || (*iter
)->getName() != name
)
1442 throw std::runtime_error("Source group not found");
1443 return SourceGroup(iter
->get());
1446 void ContextImpl::freeSourceGroup(SourceGroupImpl
*group
)
1448 auto hasher
= std::hash
<StringView
>();
1449 auto iter
= std::lower_bound(mSourceGroups
.begin(), mSourceGroups
.end(), hasher(group
->getName()),
1450 [hasher
](const UniquePtr
<SourceGroupImpl
> &lhs
, size_t rhs
) -> bool
1451 { return hasher(lhs
->getName()) < rhs
; }
1453 if(iter
!= mSourceGroups
.end() && iter
->get() == group
)
1454 mSourceGroups
.erase(iter
);
1458 void ContextImpl::setDopplerFactor(ALfloat factor
)
1460 if(!(factor
>= 0.0f
))
1461 throw std::runtime_error("Doppler factor out of range");
1463 alDopplerFactor(factor
);
1467 void ContextImpl::setSpeedOfSound(ALfloat speed
)
1470 throw std::runtime_error("Speed of sound out of range");
1472 alSpeedOfSound(speed
);
1476 void ContextImpl::setDistanceModel(DistanceModel model
)
1479 alDistanceModel((ALenum
)model
);
1483 void ContextImpl::update()
1486 mPendingSources
.erase(
1487 std::remove_if(mPendingSources
.begin(), mPendingSources
.end(),
1488 [](PendingSource
&entry
) -> bool
1489 { return !entry
.mSource
->checkPending(entry
.mFuture
); }
1490 ), mPendingSources
.end()
1492 if(!mFadingSources
.empty())
1494 auto cur_time
= std::chrono::steady_clock::now();
1495 mFadingSources
.erase(
1496 std::remove_if(mFadingSources
.begin(), mFadingSources
.end(),
1497 [cur_time
](SourceImpl
*source
) -> bool
1498 { return !source
->fadeUpdate(cur_time
); }
1499 ), mFadingSources
.end()
1503 std::remove_if(mPlaySources
.begin(), mPlaySources
.end(),
1504 [](const SourceBufferUpdateEntry
&entry
) -> bool
1505 { return !entry
.mSource
->playUpdate(entry
.mId
); }
1506 ), mPlaySources
.end()
1508 mStreamSources
.erase(
1509 std::remove_if(mStreamSources
.begin(), mStreamSources
.end(),
1510 [](const SourceStreamUpdateEntry
&entry
) -> bool
1511 { return !entry
.mSource
->playUpdate(); }
1512 ), mStreamSources
.end()
1515 if(!mWakeInterval
.load(std::memory_order_relaxed
).count())
1517 // For performance reasons, don't wait for the thread's mutex. This
1518 // should be called often enough to keep up with any and all streams
1520 mWakeThread
.notify_all();
1523 if(hasExtension(AL::EXT_disconnect
) && mIsConnected
)
1526 alcGetIntegerv(mDevice
->getALCdevice(), ALC_CONNECTED
, 1, &connected
);
1527 mIsConnected
= connected
;
1528 if(!connected
&& mMessage
.get()) mMessage
->deviceDisconnected(Device(mDevice
));
1532 void Context::destroy()
1537 DECL_THUNK0(Device
, Context
, getDevice
,)
1538 DECL_THUNK0(void, Context
, startBatch
,)
1539 DECL_THUNK0(void, Context
, endBatch
,)
1540 DECL_THUNK0(Listener
, Context
, getListener
,)
1541 DECL_THUNK1(SharedPtr
<MessageHandler
>, Context
, setMessageHandler
,, SharedPtr
<MessageHandler
>)
1542 DECL_THUNK0(SharedPtr
<MessageHandler
>, Context
, getMessageHandler
, const)
1543 DECL_THUNK1(void, Context
, setAsyncWakeInterval
,, std::chrono::milliseconds
)
1544 DECL_THUNK0(std::chrono::milliseconds
, Context
, getAsyncWakeInterval
, const)
1545 DECL_THUNK1(SharedPtr
<Decoder
>, Context
, createDecoder
,, StringView
)
1546 DECL_THUNK2(bool, Context
, isSupported
, const, ChannelConfig
, SampleType
)
1547 DECL_THUNK0(ArrayView
<String
>, Context
, getAvailableResamplers
,)
1548 DECL_THUNK0(ALsizei
, Context
, getDefaultResamplerIndex
, const)
1549 DECL_THUNK1(Buffer
, Context
, getBuffer
,, StringView
)
1550 DECL_THUNK1(SharedFuture
<Buffer
>, Context
, getBufferAsync
,, StringView
)
1551 DECL_THUNK1(void, Context
, precacheBuffersAsync
,, ArrayView
<StringView
>)
1552 DECL_THUNK2(Buffer
, Context
, createBufferFrom
,, StringView
, SharedPtr
<Decoder
>)
1553 DECL_THUNK2(SharedFuture
<Buffer
>, Context
, createBufferAsyncFrom
,, StringView
, SharedPtr
<Decoder
>)
1554 DECL_THUNK1(Buffer
, Context
, findBuffer
,, StringView
)
1555 DECL_THUNK1(SharedFuture
<Buffer
>, Context
, findBufferAsync
,, StringView
)
1556 DECL_THUNK1(void, Context
, removeBuffer
,, StringView
)
1557 DECL_THUNK1(void, Context
, removeBuffer
,, Buffer
)
1558 DECL_THUNK0(Source
, Context
, createSource
,)
1559 DECL_THUNK0(AuxiliaryEffectSlot
, Context
, createAuxiliaryEffectSlot
,)
1560 DECL_THUNK0(Effect
, Context
, createEffect
,)
1561 DECL_THUNK1(SourceGroup
, Context
, createSourceGroup
,, StringView
)
1562 DECL_THUNK1(SourceGroup
, Context
, getSourceGroup
,, StringView
)
1563 DECL_THUNK1(void, Context
, setDopplerFactor
,, ALfloat
)
1564 DECL_THUNK1(void, Context
, setSpeedOfSound
,, ALfloat
)
1565 DECL_THUNK1(void, Context
, setDistanceModel
,, DistanceModel
)
1566 DECL_THUNK0(void, Context
, update
,)
1569 void Context::MakeCurrent(Context context
)
1570 { ContextImpl::MakeCurrent(context
.pImpl
); }
1572 Context
Context::GetCurrent()
1573 { return Context(ContextImpl::GetCurrent()); }
1575 void Context::MakeThreadCurrent(Context context
)
1576 { ContextImpl::MakeThreadCurrent(context
.pImpl
); }
1578 Context
Context::GetThreadCurrent()
1579 { return Context(ContextImpl::GetThreadCurrent()); }
1582 void ListenerImpl::setGain(ALfloat gain
)
1585 throw std::runtime_error("Gain out of range");
1586 CheckContext(mContext
);
1587 alListenerf(AL_GAIN
, gain
);
1591 void ListenerImpl::set3DParameters(const Vector3
&position
, const Vector3
&velocity
, const std::pair
<Vector3
,Vector3
> &orientation
)
1593 static_assert(sizeof(orientation
) == sizeof(ALfloat
[6]), "Invalid Vector3 pair size");
1594 CheckContext(mContext
);
1595 Batcher batcher
= mContext
->getBatcher();
1596 alListenerfv(AL_POSITION
, position
.getPtr());
1597 alListenerfv(AL_VELOCITY
, velocity
.getPtr());
1598 alListenerfv(AL_ORIENTATION
, orientation
.first
.getPtr());
1601 void ListenerImpl::setPosition(ALfloat x
, ALfloat y
, ALfloat z
)
1603 CheckContext(mContext
);
1604 alListener3f(AL_POSITION
, x
, y
, z
);
1607 void ListenerImpl::setPosition(const ALfloat
*pos
)
1609 CheckContext(mContext
);
1610 alListenerfv(AL_POSITION
, pos
);
1613 void ListenerImpl::setVelocity(ALfloat x
, ALfloat y
, ALfloat z
)
1615 CheckContext(mContext
);
1616 alListener3f(AL_VELOCITY
, x
, y
, z
);
1619 void ListenerImpl::setVelocity(const ALfloat
*vel
)
1621 CheckContext(mContext
);
1622 alListenerfv(AL_VELOCITY
, vel
);
1625 void ListenerImpl::setOrientation(ALfloat x1
, ALfloat y1
, ALfloat z1
, ALfloat x2
, ALfloat y2
, ALfloat z2
)
1627 CheckContext(mContext
);
1628 ALfloat ori
[6] = { x1
, y1
, z1
, x2
, y2
, z2
};
1629 alListenerfv(AL_ORIENTATION
, ori
);
1632 void ListenerImpl::setOrientation(const ALfloat
*at
, const ALfloat
*up
)
1634 CheckContext(mContext
);
1635 ALfloat ori
[6] = { at
[0], at
[1], at
[2], up
[0], up
[1], up
[2] };
1636 alListenerfv(AL_ORIENTATION
, ori
);
1639 void ListenerImpl::setOrientation(const ALfloat
*ori
)
1641 CheckContext(mContext
);
1642 alListenerfv(AL_ORIENTATION
, ori
);
1645 void ListenerImpl::setMetersPerUnit(ALfloat m_u
)
1648 throw std::runtime_error("Invalid meters per unit");
1649 CheckContext(mContext
);
1650 if(mContext
->hasExtension(AL::EXT_EFX
))
1651 alListenerf(AL_METERS_PER_UNIT
, m_u
);
1655 using Vector3Pair
= std::pair
<Vector3
,Vector3
>;
1657 DECL_THUNK1(void, Listener
, setGain
,, ALfloat
)
1658 DECL_THUNK3(void, Listener
, set3DParameters
,, const Vector3
&, const Vector3
&, const Vector3Pair
&)
1659 DECL_THUNK3(void, Listener
, setPosition
,, ALfloat
, ALfloat
, ALfloat
)
1660 DECL_THUNK1(void, Listener
, setPosition
,, const ALfloat
*)
1661 DECL_THUNK3(void, Listener
, setVelocity
,, ALfloat
, ALfloat
, ALfloat
)
1662 DECL_THUNK1(void, Listener
, setVelocity
,, const ALfloat
*)
1663 DECL_THUNK6(void, Listener
, setOrientation
,, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
, ALfloat
)
1664 DECL_THUNK2(void, Listener
, setOrientation
,, const ALfloat
*, const ALfloat
*)
1665 DECL_THUNK1(void, Listener
, setOrientation
,, const ALfloat
*)
1666 DECL_THUNK1(void, Listener
, setMetersPerUnit
,, ALfloat
)