12 #include <string_view>
14 #include <unordered_map>
24 using namespace std::string_view_literals
;
26 struct FuncExportEntry
{
30 #define DECL(x) FuncExportEntry{ #x, reinterpret_cast<void*>(x) }
31 const std::array alcFunctions
{
32 DECL(alcCreateContext
),
33 DECL(alcMakeContextCurrent
),
34 DECL(alcProcessContext
),
35 DECL(alcSuspendContext
),
36 DECL(alcDestroyContext
),
37 DECL(alcGetCurrentContext
),
38 DECL(alcGetContextsDevice
),
42 DECL(alcIsExtensionPresent
),
43 DECL(alcGetProcAddress
),
44 DECL(alcGetEnumValue
),
47 DECL(alcCaptureOpenDevice
),
48 DECL(alcCaptureCloseDevice
),
49 DECL(alcCaptureStart
),
51 DECL(alcCaptureSamples
),
53 DECL(alcSetThreadContext
),
54 DECL(alcGetThreadContext
),
69 DECL(alIsExtensionPresent
),
70 DECL(alGetProcAddress
),
79 DECL(alGetListener3f
),
80 DECL(alGetListenerfv
),
82 DECL(alGetListener3i
),
83 DECL(alGetListeneriv
),
85 DECL(alDeleteSources
),
101 DECL(alSourceRewindv
),
102 DECL(alSourcePausev
),
105 DECL(alSourceRewind
),
107 DECL(alSourceQueueBuffers
),
108 DECL(alSourceUnqueueBuffers
),
110 DECL(alDeleteBuffers
),
125 DECL(alDopplerFactor
),
126 DECL(alDopplerVelocity
),
127 DECL(alSpeedOfSound
),
128 DECL(alDistanceModel
),
132 DECL(alDeleteFilters
),
143 DECL(alDeleteEffects
),
153 DECL(alGenAuxiliaryEffectSlots
),
154 DECL(alDeleteAuxiliaryEffectSlots
),
155 DECL(alIsAuxiliaryEffectSlot
),
156 DECL(alAuxiliaryEffectSlotf
),
157 DECL(alAuxiliaryEffectSlotfv
),
158 DECL(alAuxiliaryEffectSloti
),
159 DECL(alAuxiliaryEffectSlotiv
),
160 DECL(alGetAuxiliaryEffectSlotf
),
161 DECL(alGetAuxiliaryEffectSlotfv
),
162 DECL(alGetAuxiliaryEffectSloti
),
163 DECL(alGetAuxiliaryEffectSlotiv
),
167 struct EnumExportEntry
{
168 const ALCchar
*enumName
;
171 #define DECL(x) EnumExportEntry{ #x, (x) }
172 const std::array alcEnumerations
{
177 DECL(ALC_MAJOR_VERSION
),
178 DECL(ALC_MINOR_VERSION
),
179 DECL(ALC_ATTRIBUTES_SIZE
),
180 DECL(ALC_ALL_ATTRIBUTES
),
181 DECL(ALC_DEFAULT_DEVICE_SPECIFIER
),
182 DECL(ALC_DEVICE_SPECIFIER
),
183 DECL(ALC_ALL_DEVICES_SPECIFIER
),
184 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER
),
185 DECL(ALC_EXTENSIONS
),
189 DECL(ALC_MONO_SOURCES
),
190 DECL(ALC_STEREO_SOURCES
),
191 DECL(ALC_CAPTURE_DEVICE_SPECIFIER
),
192 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
),
193 DECL(ALC_CAPTURE_SAMPLES
),
196 DECL(ALC_INVALID_DEVICE
),
197 DECL(ALC_INVALID_CONTEXT
),
198 DECL(ALC_INVALID_ENUM
),
199 DECL(ALC_INVALID_VALUE
),
200 DECL(ALC_OUT_OF_MEMORY
),
207 DECL(AL_SOURCE_RELATIVE
),
208 DECL(AL_CONE_INNER_ANGLE
),
209 DECL(AL_CONE_OUTER_ANGLE
),
219 DECL(AL_ORIENTATION
),
220 DECL(AL_REFERENCE_DISTANCE
),
221 DECL(AL_ROLLOFF_FACTOR
),
222 DECL(AL_CONE_OUTER_GAIN
),
223 DECL(AL_MAX_DISTANCE
),
225 DECL(AL_SAMPLE_OFFSET
),
226 DECL(AL_BYTE_OFFSET
),
227 DECL(AL_SOURCE_TYPE
),
230 DECL(AL_UNDETERMINED
),
232 DECL(AL_SOURCE_STATE
),
238 DECL(AL_BUFFERS_QUEUED
),
239 DECL(AL_BUFFERS_PROCESSED
),
241 DECL(AL_FORMAT_MONO8
),
242 DECL(AL_FORMAT_MONO16
),
243 DECL(AL_FORMAT_STEREO8
),
244 DECL(AL_FORMAT_STEREO16
),
256 DECL(AL_INVALID_NAME
),
257 DECL(AL_INVALID_ENUM
),
258 DECL(AL_INVALID_VALUE
),
259 DECL(AL_INVALID_OPERATION
),
260 DECL(AL_OUT_OF_MEMORY
),
267 DECL(AL_DOPPLER_FACTOR
),
268 DECL(AL_DOPPLER_VELOCITY
),
269 DECL(AL_DISTANCE_MODEL
),
270 DECL(AL_SPEED_OF_SOUND
),
272 DECL(AL_INVERSE_DISTANCE
),
273 DECL(AL_INVERSE_DISTANCE_CLAMPED
),
274 DECL(AL_LINEAR_DISTANCE
),
275 DECL(AL_LINEAR_DISTANCE_CLAMPED
),
276 DECL(AL_EXPONENT_DISTANCE
),
277 DECL(AL_EXPONENT_DISTANCE_CLAMPED
),
281 [[nodiscard
]] constexpr auto GetNoErrorString() noexcept
{ return "No Error"; }
282 [[nodiscard
]] constexpr auto GetInvalidDeviceString() noexcept
{ return "Invalid Device"; }
283 [[nodiscard
]] constexpr auto GetInvalidContextString() noexcept
{ return "Invalid Context"; }
284 [[nodiscard
]] constexpr auto GetInvalidEnumString() noexcept
{ return "Invalid Enum"; }
285 [[nodiscard
]] constexpr auto GetInvalidValueString() noexcept
{ return "Invalid Value"; }
286 [[nodiscard
]] constexpr auto GetOutOfMemoryString() noexcept
{ return "Out of Memory"; }
288 [[nodiscard
]] constexpr auto GetExtensionList() noexcept
-> std::string_view
290 return "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
291 "ALC_EXT_thread_local_context"sv
;
294 constexpr ALCint alcMajorVersion
= 1;
295 constexpr ALCint alcMinorVersion
= 1;
298 std::recursive_mutex EnumerationLock
;
299 std::mutex ContextSwitchLock
;
301 std::atomic
<ALCenum
> LastError
{ALC_NO_ERROR
};
302 std::unordered_map
<ALCdevice
*,ALCuint
> DeviceIfaceMap
;
303 std::unordered_map
<ALCcontext
*,ALCuint
> ContextIfaceMap
;
305 template<typename T
, typename U
, typename V
>
306 auto maybe_get(std::unordered_map
<T
,U
> &list
, V
&& key
) -> std::optional
<U
>
308 auto iter
= list
.find(std::forward
<V
>(key
));
309 if(iter
!= list
.end()) return iter
->second
;
314 struct EnumeratedList
{
315 std::vector
<ALCchar
> Names
;
316 std::vector
<ALCuint
> Indicies
;
324 void AppendDeviceList(const ALCchar
*names
, ALCuint idx
);
326 auto GetDriverIndexForName(const std::string_view name
) const -> std::optional
<ALCuint
>;
328 EnumeratedList DevicesList
;
329 EnumeratedList AllDevicesList
;
330 EnumeratedList CaptureDevicesList
;
332 void EnumeratedList::AppendDeviceList(const ALCchar
* names
, ALCuint idx
)
334 const ALCchar
*name_end
= names
;
335 if(!name_end
) return;
340 TRACE("Enumerated \"%s\", driver %u\n", name_end
, idx
);
342 name_end
+= strlen(name_end
)+1; /* NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
344 if(names
== name_end
)
347 Names
.reserve(Names
.size() + static_cast<size_t>(name_end
- names
) + 1);
348 Names
.insert(Names
.cend(), names
, name_end
);
350 Indicies
.reserve(Indicies
.size() + count
);
351 Indicies
.insert(Indicies
.cend(), count
, idx
);
354 auto EnumeratedList::GetDriverIndexForName(const std::string_view name
) const -> std::optional
<ALCuint
>
356 auto devnames
= Names
.cbegin();
357 auto index
= Indicies
.cbegin();
359 while(devnames
!= Names
.cend() && *devnames
)
361 const auto devname
= std::string_view
{al::to_address(devnames
)};
362 if(name
== devname
) return *index
;
364 devnames
+= ptrdiff_t(devname
.size()+1);
371 void InitCtxFuncs(DriverIface
&iface
)
373 ALCdevice
*device
{iface
.alcGetContextsDevice(iface
.alcGetCurrentContext())};
375 #define LOAD_PROC(x) do { \
376 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
378 ERR("Failed to find entry point for %s in %ls\n", #x, \
379 iface.Name.c_str()); \
381 if(iface
.alcIsExtensionPresent(device
, "ALC_EXT_EFX"))
383 LOAD_PROC(alGenFilters
);
384 LOAD_PROC(alDeleteFilters
);
385 LOAD_PROC(alIsFilter
);
386 LOAD_PROC(alFilterf
);
387 LOAD_PROC(alFilterfv
);
388 LOAD_PROC(alFilteri
);
389 LOAD_PROC(alFilteriv
);
390 LOAD_PROC(alGetFilterf
);
391 LOAD_PROC(alGetFilterfv
);
392 LOAD_PROC(alGetFilteri
);
393 LOAD_PROC(alGetFilteriv
);
394 LOAD_PROC(alGenEffects
);
395 LOAD_PROC(alDeleteEffects
);
396 LOAD_PROC(alIsEffect
);
397 LOAD_PROC(alEffectf
);
398 LOAD_PROC(alEffectfv
);
399 LOAD_PROC(alEffecti
);
400 LOAD_PROC(alEffectiv
);
401 LOAD_PROC(alGetEffectf
);
402 LOAD_PROC(alGetEffectfv
);
403 LOAD_PROC(alGetEffecti
);
404 LOAD_PROC(alGetEffectiv
);
405 LOAD_PROC(alGenAuxiliaryEffectSlots
);
406 LOAD_PROC(alDeleteAuxiliaryEffectSlots
);
407 LOAD_PROC(alIsAuxiliaryEffectSlot
);
408 LOAD_PROC(alAuxiliaryEffectSlotf
);
409 LOAD_PROC(alAuxiliaryEffectSlotfv
);
410 LOAD_PROC(alAuxiliaryEffectSloti
);
411 LOAD_PROC(alAuxiliaryEffectSlotiv
);
412 LOAD_PROC(alGetAuxiliaryEffectSlotf
);
413 LOAD_PROC(alGetAuxiliaryEffectSlotfv
);
414 LOAD_PROC(alGetAuxiliaryEffectSloti
);
415 LOAD_PROC(alGetAuxiliaryEffectSlotiv
);
423 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*devicename
) noexcept
425 ALCdevice
*device
{nullptr};
426 std::optional
<ALCuint
> idx
;
428 /* Prior to the enumeration extension, apps would hardcode these names as a
429 * quality hint for the wrapper driver. Ignore them since there's no sane
432 if(devicename
&& *devicename
!= '\0' && devicename
!= "DirectSound3D"sv
433 && devicename
!= "DirectSound"sv
&& devicename
!= "MMSYSTEM"sv
)
436 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
437 if(DevicesList
.Names
.empty())
438 std::ignore
= alcGetString(nullptr, ALC_DEVICE_SPECIFIER
);
439 idx
= DevicesList
.GetDriverIndexForName(devicename
);
442 if(AllDevicesList
.Names
.empty())
443 std::ignore
= alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
);
444 idx
= AllDevicesList
.GetDriverIndexForName(devicename
);
450 LastError
.store(ALC_INVALID_VALUE
);
451 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
454 TRACE("Found driver %u for name \"%s\"\n", *idx
, devicename
);
455 device
= DriverList
[*idx
]->alcOpenDevice(devicename
);
460 for(const auto &drv
: DriverList
)
462 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
463 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
465 TRACE("Using default device from driver %u\n", drvidx
);
466 device
= drv
->alcOpenDevice(nullptr);
477 DeviceIfaceMap
.emplace(device
, idx
.value());
480 DriverList
[idx
.value()]->alcCloseDevice(device
);
488 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
) noexcept
490 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
492 if(!DriverList
[*idx
]->alcCloseDevice(device
))
494 DeviceIfaceMap
.erase(device
);
498 LastError
.store(ALC_INVALID_DEVICE
);
503 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrlist
) noexcept
505 const auto idx
= maybe_get(DeviceIfaceMap
, device
);
508 LastError
.store(ALC_INVALID_DEVICE
);
512 ALCcontext
*context
{DriverList
[*idx
]->alcCreateContext(device
, attrlist
)};
516 ContextIfaceMap
.emplace(context
, *idx
);
519 DriverList
[*idx
]->alcDestroyContext(context
);
527 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
) noexcept
529 std::lock_guard
<std::mutex
> ctxlock
{ContextSwitchLock
};
531 std::optional
<ALCuint
> idx
;
534 idx
= maybe_get(ContextIfaceMap
, context
);
537 LastError
.store(ALC_INVALID_CONTEXT
);
540 if(!DriverList
[*idx
]->alcMakeContextCurrent(context
))
543 std::call_once(DriverList
[*idx
]->InitOnceCtx
, [idx
]{ InitCtxFuncs(*DriverList
[*idx
]); });
546 /* Unset the context from the old driver if it's different from the new
551 DriverIface
*oldiface
{GetThreadDriver()};
552 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
553 oldiface
= CurrentCtxDriver
.exchange(nullptr);
554 if(oldiface
) oldiface
->alcMakeContextCurrent(nullptr);
558 DriverIface
*oldiface
{GetThreadDriver()};
559 if(oldiface
&& oldiface
!= DriverList
[*idx
].get())
560 oldiface
->alcSetThreadContext(nullptr);
561 oldiface
= CurrentCtxDriver
.exchange(DriverList
[*idx
].get());
562 if(oldiface
&& oldiface
!= DriverList
[*idx
].get())
563 oldiface
->alcMakeContextCurrent(nullptr);
565 SetThreadDriver(nullptr);
570 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
) noexcept
572 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
573 return DriverList
[*idx
]->alcProcessContext(context
);
575 LastError
.store(ALC_INVALID_CONTEXT
);
578 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
) noexcept
580 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
581 return DriverList
[*idx
]->alcSuspendContext(context
);
583 LastError
.store(ALC_INVALID_CONTEXT
);
586 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
) noexcept
588 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
590 DriverList
[*idx
]->alcDestroyContext(context
);
591 ContextIfaceMap
.erase(context
);
594 LastError
.store(ALC_INVALID_CONTEXT
);
597 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext() noexcept
599 DriverIface
*iface
{GetThreadDriver()};
600 if(!iface
) iface
= CurrentCtxDriver
.load();
601 return iface
? iface
->alcGetCurrentContext() : nullptr;
604 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*context
) noexcept
606 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
607 return DriverList
[*idx
]->alcGetContextsDevice(context
);
609 LastError
.store(ALC_INVALID_CONTEXT
);
614 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
) noexcept
618 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
619 return DriverList
[*idx
]->alcGetError(device
);
620 return ALC_INVALID_DEVICE
;
622 return LastError
.exchange(ALC_NO_ERROR
);
625 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extname
) noexcept
629 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
630 return DriverList
[*idx
]->alcIsExtensionPresent(device
, extname
);
632 LastError
.store(ALC_INVALID_DEVICE
);
636 const auto tofind
= std::string_view
{extname
};
637 const auto extlist
= GetExtensionList();
638 auto matchpos
= extlist
.find(tofind
);
639 while(matchpos
!= std::string_view::npos
)
641 const auto endpos
= matchpos
+ tofind
.size();
642 if((matchpos
== 0 || std::isspace(extlist
[matchpos
-1]))
643 && (endpos
== extlist
.size() || std::isspace(extlist
[endpos
])))
645 matchpos
= extlist
.find(tofind
, matchpos
+1);
650 ALC_API
void* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcname
) noexcept
654 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
655 return DriverList
[*idx
]->alcGetProcAddress(device
, funcname
);
657 LastError
.store(ALC_INVALID_DEVICE
);
661 auto iter
= std::find_if(alcFunctions
.cbegin(), alcFunctions
.cend(),
662 [funcname
](const FuncExportEntry
&entry
) -> bool
663 { return strcmp(funcname
, entry
.funcName
) == 0; }
665 return (iter
!= alcFunctions
.cend()) ? iter
->address
: nullptr;
668 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumname
) noexcept
672 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
673 return DriverList
[*idx
]->alcGetEnumValue(device
, enumname
);
675 LastError
.store(ALC_INVALID_DEVICE
);
679 auto iter
= std::find_if(alcEnumerations
.cbegin(), alcEnumerations
.cend(),
680 [enumname
](const EnumExportEntry
&entry
) -> bool
681 { return strcmp(enumname
, entry
.enumName
) == 0; }
683 return (iter
!= alcEnumerations
.cend()) ? iter
->value
: 0;
686 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetString(ALCdevice
*device
, ALCenum param
) noexcept
690 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
691 return DriverList
[*idx
]->alcGetString(device
, param
);
693 LastError
.store(ALC_INVALID_DEVICE
);
699 case ALC_NO_ERROR
: return GetNoErrorString();
700 case ALC_INVALID_ENUM
: return GetInvalidEnumString();
701 case ALC_INVALID_VALUE
: return GetInvalidValueString();
702 case ALC_INVALID_DEVICE
: return GetInvalidDeviceString();
703 case ALC_INVALID_CONTEXT
: return GetInvalidContextString();
704 case ALC_OUT_OF_MEMORY
: return GetOutOfMemoryString();
705 case ALC_EXTENSIONS
: return GetExtensionList().data();
707 case ALC_DEVICE_SPECIFIER
:
709 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
712 for(const auto &drv
: DriverList
)
714 /* Only enumerate names from drivers that support it. */
715 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
716 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
717 DevicesList
.AppendDeviceList(drv
->alcGetString(nullptr,ALC_DEVICE_SPECIFIER
), idx
);
720 /* Ensure the list is double-null termianted. */
721 if(DevicesList
.Names
.empty())
722 DevicesList
.Names
.emplace_back('\0');
723 DevicesList
.Names
.emplace_back('\0');
724 return DevicesList
.Names
.data();
727 case ALC_ALL_DEVICES_SPECIFIER
:
729 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
730 AllDevicesList
.clear();
732 for(const auto &drv
: DriverList
)
734 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
735 * standard enumeration.
737 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
738 AllDevicesList
.AppendDeviceList(
739 drv
->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
), idx
);
740 else if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
741 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
742 AllDevicesList
.AppendDeviceList(
743 drv
->alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
746 /* Ensure the list is double-null termianted. */
747 if(AllDevicesList
.Names
.empty())
748 AllDevicesList
.Names
.emplace_back('\0');
749 AllDevicesList
.Names
.emplace_back('\0');
750 return AllDevicesList
.Names
.data();
753 case ALC_CAPTURE_DEVICE_SPECIFIER
:
755 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
756 CaptureDevicesList
.clear();
758 for(const auto &drv
: DriverList
)
760 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
761 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
762 CaptureDevicesList
.AppendDeviceList(
763 drv
->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
), idx
);
766 /* Ensure the list is double-null termianted. */
767 if(CaptureDevicesList
.Names
.empty())
768 CaptureDevicesList
.Names
.emplace_back('\0');
769 CaptureDevicesList
.Names
.emplace_back('\0');
770 return CaptureDevicesList
.Names
.data();
773 case ALC_DEFAULT_DEVICE_SPECIFIER
:
775 for(const auto &drv
: DriverList
)
777 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
778 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
779 return drv
->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER
);
784 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
786 for(const auto &drv
: DriverList
)
788 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE
)
789 return drv
->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER
);
794 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
796 for(const auto &drv
: DriverList
)
798 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
799 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
800 return drv
->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
);
806 LastError
.store(ALC_INVALID_ENUM
);
812 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
) noexcept
816 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
817 return DriverList
[*idx
]->alcGetIntegerv(device
, param
, size
, values
);
819 LastError
.store(ALC_INVALID_DEVICE
);
823 if(size
<= 0 || values
== nullptr)
825 LastError
.store(ALC_INVALID_VALUE
);
831 case ALC_MAJOR_VERSION
:
834 *values
= alcMajorVersion
;
837 LastError
.store(ALC_INVALID_VALUE
);
839 case ALC_MINOR_VERSION
:
842 *values
= alcMinorVersion
;
845 LastError
.store(ALC_INVALID_VALUE
);
848 case ALC_ATTRIBUTES_SIZE
:
849 case ALC_ALL_ATTRIBUTES
:
853 case ALC_MONO_SOURCES
:
854 case ALC_STEREO_SOURCES
:
855 case ALC_CAPTURE_SAMPLES
:
856 LastError
.store(ALC_INVALID_DEVICE
);
860 LastError
.store(ALC_INVALID_ENUM
);
866 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*devicename
, ALCuint frequency
,
867 ALCenum format
, ALCsizei buffersize
) noexcept
869 ALCdevice
*device
{nullptr};
870 std::optional
<ALCuint
> idx
;
872 if(devicename
&& *devicename
!= '\0')
875 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
876 if(CaptureDevicesList
.Names
.empty())
877 std::ignore
= alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
);
878 idx
= CaptureDevicesList
.GetDriverIndexForName(devicename
);
883 LastError
.store(ALC_INVALID_VALUE
);
884 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
887 TRACE("Found driver %u for name \"%s\"\n", *idx
, devicename
);
888 device
= DriverList
[*idx
]->alcCaptureOpenDevice(devicename
, frequency
, format
, buffersize
);
893 for(const auto &drv
: DriverList
)
895 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
896 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
898 TRACE("Using default capture device from driver %u\n", drvidx
);
899 device
= drv
->alcCaptureOpenDevice(nullptr, frequency
, format
, buffersize
);
910 DeviceIfaceMap
.emplace(device
, idx
.value());
913 DriverList
[idx
.value()]->alcCaptureCloseDevice(device
);
921 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
) noexcept
923 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
925 if(!DriverList
[*idx
]->alcCaptureCloseDevice(device
))
927 DeviceIfaceMap
.erase(device
);
931 LastError
.store(ALC_INVALID_DEVICE
);
935 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
) noexcept
937 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
938 return DriverList
[*idx
]->alcCaptureStart(device
);
939 LastError
.store(ALC_INVALID_DEVICE
);
942 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
) noexcept
944 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
945 return DriverList
[*idx
]->alcCaptureStop(device
);
946 LastError
.store(ALC_INVALID_DEVICE
);
949 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
) noexcept
951 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
952 return DriverList
[*idx
]->alcCaptureSamples(device
, buffer
, samples
);
953 LastError
.store(ALC_INVALID_DEVICE
);
957 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
) noexcept
961 DriverIface
*oldiface
{GetThreadDriver()};
962 if(oldiface
&& !oldiface
->alcSetThreadContext(nullptr))
964 SetThreadDriver(nullptr);
968 ALCenum err
{ALC_INVALID_CONTEXT
};
969 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
971 if(DriverList
[*idx
]->alcSetThreadContext(context
))
973 std::call_once(DriverList
[*idx
]->InitOnceCtx
, [idx
]{InitCtxFuncs(*DriverList
[*idx
]);});
975 DriverIface
*oldiface
{GetThreadDriver()};
976 if(oldiface
!= DriverList
[*idx
].get())
978 SetThreadDriver(DriverList
[*idx
].get());
979 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
983 err
= DriverList
[*idx
]->alcGetError(nullptr);
985 LastError
.store(err
);
989 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext() noexcept
991 if(DriverIface
*iface
{GetThreadDriver()})
992 return iface
->alcGetThreadContext();