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
*,ALint
> DeviceIfaceMap
;
303 std::unordered_map
<ALCcontext
*,ALint
> ContextIfaceMap
;
305 template<typename T
, typename U
, typename V
>
306 std::optional
<U
> maybe_get(std::unordered_map
<T
,U
> &list
, V
&& key
)
308 auto iter
= list
.find(std::forward
<V
>(key
));
309 if(iter
== list
.end()) return std::nullopt
;
314 struct EnumeratedList
{
315 std::vector
<ALCchar
> Names
;
316 std::vector
<ALCint
> Indicies
;
324 void AppendDeviceList(const ALCchar
*names
, ALint idx
);
326 auto GetDriverIndexForName(const std::string_view name
) const -> ALint
;
328 EnumeratedList DevicesList
;
329 EnumeratedList AllDevicesList
;
330 EnumeratedList CaptureDevicesList
;
332 void EnumeratedList::AppendDeviceList(const ALCchar
* names
, ALint idx
)
334 const ALCchar
*name_end
= names
;
335 if(!name_end
) return;
340 TRACE("Enumerated \"%s\", driver %d\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 -> ALint
356 auto devnames
= Names
.cbegin();
357 auto index
= Indicies
.cbegin();
359 while(devnames
!= Names
.cend() && *devnames
)
361 if(name
== al::to_address(devnames
))
363 devnames
+= ptrdiff_t(strlen(al::to_address(devnames
))+1);
370 void InitCtxFuncs(DriverIface
&iface
)
372 ALCdevice
*device
{iface
.alcGetContextsDevice(iface
.alcGetCurrentContext())};
374 #define LOAD_PROC(x) do { \
375 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
377 ERR("Failed to find entry point for %s in %ls\n", #x, \
378 iface.Name.c_str()); \
380 if(iface
.alcIsExtensionPresent(device
, "ALC_EXT_EFX"))
382 LOAD_PROC(alGenFilters
);
383 LOAD_PROC(alDeleteFilters
);
384 LOAD_PROC(alIsFilter
);
385 LOAD_PROC(alFilterf
);
386 LOAD_PROC(alFilterfv
);
387 LOAD_PROC(alFilteri
);
388 LOAD_PROC(alFilteriv
);
389 LOAD_PROC(alGetFilterf
);
390 LOAD_PROC(alGetFilterfv
);
391 LOAD_PROC(alGetFilteri
);
392 LOAD_PROC(alGetFilteriv
);
393 LOAD_PROC(alGenEffects
);
394 LOAD_PROC(alDeleteEffects
);
395 LOAD_PROC(alIsEffect
);
396 LOAD_PROC(alEffectf
);
397 LOAD_PROC(alEffectfv
);
398 LOAD_PROC(alEffecti
);
399 LOAD_PROC(alEffectiv
);
400 LOAD_PROC(alGetEffectf
);
401 LOAD_PROC(alGetEffectfv
);
402 LOAD_PROC(alGetEffecti
);
403 LOAD_PROC(alGetEffectiv
);
404 LOAD_PROC(alGenAuxiliaryEffectSlots
);
405 LOAD_PROC(alDeleteAuxiliaryEffectSlots
);
406 LOAD_PROC(alIsAuxiliaryEffectSlot
);
407 LOAD_PROC(alAuxiliaryEffectSlotf
);
408 LOAD_PROC(alAuxiliaryEffectSlotfv
);
409 LOAD_PROC(alAuxiliaryEffectSloti
);
410 LOAD_PROC(alAuxiliaryEffectSlotiv
);
411 LOAD_PROC(alGetAuxiliaryEffectSlotf
);
412 LOAD_PROC(alGetAuxiliaryEffectSlotfv
);
413 LOAD_PROC(alGetAuxiliaryEffectSloti
);
414 LOAD_PROC(alGetAuxiliaryEffectSlotiv
);
422 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*devicename
) noexcept
424 ALCdevice
*device
{nullptr};
427 /* Prior to the enumeration extension, apps would hardcode these names as a
428 * quality hint for the wrapper driver. Ignore them since there's no sane
431 if(devicename
&& (*devicename
== '\0' || devicename
== "DirectSound3D"sv
432 || devicename
== "DirectSound"sv
|| devicename
== "MMSYSTEM"sv
))
433 devicename
= nullptr;
437 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
438 if(DevicesList
.Names
.empty())
439 std::ignore
= alcGetString(nullptr, ALC_DEVICE_SPECIFIER
);
440 idx
= DevicesList
.GetDriverIndexForName(devicename
);
443 if(AllDevicesList
.Names
.empty())
444 std::ignore
= alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
);
445 idx
= AllDevicesList
.GetDriverIndexForName(devicename
);
451 LastError
.store(ALC_INVALID_VALUE
);
452 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
455 TRACE("Found driver %d for name \"%s\"\n", idx
, devicename
);
456 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 %d\n", idx
);
466 device
= drv
->alcOpenDevice(nullptr);
476 DeviceIfaceMap
.emplace(device
, idx
);
479 DriverList
[idx
]->alcCloseDevice(device
);
487 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
) noexcept
489 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
491 if(!DriverList
[*idx
]->alcCloseDevice(device
))
493 DeviceIfaceMap
.erase(device
);
497 LastError
.store(ALC_INVALID_DEVICE
);
502 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrlist
) noexcept
504 const auto idx
= maybe_get(DeviceIfaceMap
, device
);
507 LastError
.store(ALC_INVALID_DEVICE
);
511 ALCcontext
*context
{DriverList
[*idx
]->alcCreateContext(device
, attrlist
)};
515 ContextIfaceMap
.emplace(context
, *idx
);
518 DriverList
[*idx
]->alcDestroyContext(context
);
526 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
) noexcept
528 std::lock_guard
<std::mutex
> ctxlock
{ContextSwitchLock
};
530 std::optional
<ALint
> idx
;
533 idx
= maybe_get(ContextIfaceMap
, context
);
536 LastError
.store(ALC_INVALID_CONTEXT
);
539 if(!DriverList
[*idx
]->alcMakeContextCurrent(context
))
542 std::call_once(DriverList
[*idx
]->InitOnceCtx
, [idx
]{ InitCtxFuncs(*DriverList
[*idx
]); });
545 /* Unset the context from the old driver if it's different from the new
550 DriverIface
*oldiface
{GetThreadDriver()};
551 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
552 oldiface
= CurrentCtxDriver
.exchange(nullptr);
553 if(oldiface
) oldiface
->alcMakeContextCurrent(nullptr);
557 DriverIface
*oldiface
{GetThreadDriver()};
558 if(oldiface
&& oldiface
!= DriverList
[*idx
].get())
559 oldiface
->alcSetThreadContext(nullptr);
560 oldiface
= CurrentCtxDriver
.exchange(DriverList
[*idx
].get());
561 if(oldiface
&& oldiface
!= DriverList
[*idx
].get())
562 oldiface
->alcMakeContextCurrent(nullptr);
564 SetThreadDriver(nullptr);
569 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
) noexcept
571 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
572 return DriverList
[*idx
]->alcProcessContext(context
);
574 LastError
.store(ALC_INVALID_CONTEXT
);
577 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
) noexcept
579 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
580 return DriverList
[*idx
]->alcSuspendContext(context
);
582 LastError
.store(ALC_INVALID_CONTEXT
);
585 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
) noexcept
587 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
589 DriverList
[*idx
]->alcDestroyContext(context
);
590 ContextIfaceMap
.erase(context
);
593 LastError
.store(ALC_INVALID_CONTEXT
);
596 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext() noexcept
598 DriverIface
*iface
{GetThreadDriver()};
599 if(!iface
) iface
= CurrentCtxDriver
.load();
600 return iface
? iface
->alcGetCurrentContext() : nullptr;
603 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*context
) noexcept
605 if(const auto idx
= maybe_get(ContextIfaceMap
, context
))
606 return DriverList
[*idx
]->alcGetContextsDevice(context
);
608 LastError
.store(ALC_INVALID_CONTEXT
);
613 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
) noexcept
617 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
618 return DriverList
[*idx
]->alcGetError(device
);
619 return ALC_INVALID_DEVICE
;
621 return LastError
.exchange(ALC_NO_ERROR
);
624 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extname
) noexcept
628 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
629 return DriverList
[*idx
]->alcIsExtensionPresent(device
, extname
);
631 LastError
.store(ALC_INVALID_DEVICE
);
635 const auto tofind
= std::string_view
{extname
};
636 const auto extlist
= GetExtensionList();
637 auto matchpos
= extlist
.find(tofind
);
638 while(matchpos
!= std::string_view::npos
)
640 const auto endpos
= matchpos
+ tofind
.size();
641 if((matchpos
== 0 || std::isspace(extlist
[matchpos
-1]))
642 && (endpos
== extlist
.size() || std::isspace(extlist
[endpos
])))
644 matchpos
= extlist
.find(tofind
, matchpos
+1);
649 ALC_API
void* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcname
) noexcept
653 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
654 return DriverList
[*idx
]->alcGetProcAddress(device
, funcname
);
656 LastError
.store(ALC_INVALID_DEVICE
);
660 auto iter
= std::find_if(alcFunctions
.cbegin(), alcFunctions
.cend(),
661 [funcname
](const FuncExportEntry
&entry
) -> bool
662 { return strcmp(funcname
, entry
.funcName
) == 0; }
664 return (iter
!= alcFunctions
.cend()) ? iter
->address
: nullptr;
667 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumname
) noexcept
671 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
672 return DriverList
[*idx
]->alcGetEnumValue(device
, enumname
);
674 LastError
.store(ALC_INVALID_DEVICE
);
678 auto iter
= std::find_if(alcEnumerations
.cbegin(), alcEnumerations
.cend(),
679 [enumname
](const EnumExportEntry
&entry
) -> bool
680 { return strcmp(enumname
, entry
.enumName
) == 0; }
682 return (iter
!= alcEnumerations
.cend()) ? iter
->value
: 0;
685 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetString(ALCdevice
*device
, ALCenum param
) noexcept
689 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
690 return DriverList
[*idx
]->alcGetString(device
, param
);
692 LastError
.store(ALC_INVALID_DEVICE
);
698 case ALC_NO_ERROR
: return GetNoErrorString();
699 case ALC_INVALID_ENUM
: return GetInvalidEnumString();
700 case ALC_INVALID_VALUE
: return GetInvalidValueString();
701 case ALC_INVALID_DEVICE
: return GetInvalidDeviceString();
702 case ALC_INVALID_CONTEXT
: return GetInvalidContextString();
703 case ALC_OUT_OF_MEMORY
: return GetOutOfMemoryString();
704 case ALC_EXTENSIONS
: return GetExtensionList().data();
706 case ALC_DEVICE_SPECIFIER
:
708 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
711 for(const auto &drv
: DriverList
)
713 /* Only enumerate names from drivers that support it. */
714 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
715 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
716 DevicesList
.AppendDeviceList(drv
->alcGetString(nullptr,ALC_DEVICE_SPECIFIER
), idx
);
719 /* Ensure the list is double-null termianted. */
720 if(DevicesList
.Names
.empty())
721 DevicesList
.Names
.emplace_back('\0');
722 DevicesList
.Names
.emplace_back('\0');
723 return DevicesList
.Names
.data();
726 case ALC_ALL_DEVICES_SPECIFIER
:
728 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
729 AllDevicesList
.clear();
731 for(const auto &drv
: DriverList
)
733 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
734 * standard enumeration.
736 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
737 AllDevicesList
.AppendDeviceList(
738 drv
->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
), idx
);
739 else if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
740 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
741 AllDevicesList
.AppendDeviceList(
742 drv
->alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
745 /* Ensure the list is double-null termianted. */
746 if(AllDevicesList
.Names
.empty())
747 AllDevicesList
.Names
.emplace_back('\0');
748 AllDevicesList
.Names
.emplace_back('\0');
749 return AllDevicesList
.Names
.data();
752 case ALC_CAPTURE_DEVICE_SPECIFIER
:
754 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
755 CaptureDevicesList
.clear();
757 for(const auto &drv
: DriverList
)
759 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
760 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
761 CaptureDevicesList
.AppendDeviceList(
762 drv
->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
), idx
);
765 /* Ensure the list is double-null termianted. */
766 if(CaptureDevicesList
.Names
.empty())
767 CaptureDevicesList
.Names
.emplace_back('\0');
768 CaptureDevicesList
.Names
.emplace_back('\0');
769 return CaptureDevicesList
.Names
.data();
772 case ALC_DEFAULT_DEVICE_SPECIFIER
:
774 for(const auto &drv
: DriverList
)
776 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
777 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
778 return drv
->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER
);
783 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
785 for(const auto &drv
: DriverList
)
787 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE
)
788 return drv
->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER
);
793 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
795 for(const auto &drv
: DriverList
)
797 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
798 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
799 return drv
->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
);
805 LastError
.store(ALC_INVALID_ENUM
);
811 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
) noexcept
815 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
816 return DriverList
[*idx
]->alcGetIntegerv(device
, param
, size
, values
);
818 LastError
.store(ALC_INVALID_DEVICE
);
822 if(size
<= 0 || values
== nullptr)
824 LastError
.store(ALC_INVALID_VALUE
);
830 case ALC_MAJOR_VERSION
:
833 *values
= alcMajorVersion
;
837 case ALC_MINOR_VERSION
:
840 *values
= alcMinorVersion
;
843 LastError
.store(ALC_INVALID_VALUE
);
846 case ALC_ATTRIBUTES_SIZE
:
847 case ALC_ALL_ATTRIBUTES
:
851 case ALC_MONO_SOURCES
:
852 case ALC_STEREO_SOURCES
:
853 case ALC_CAPTURE_SAMPLES
:
854 LastError
.store(ALC_INVALID_DEVICE
);
858 LastError
.store(ALC_INVALID_ENUM
);
864 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*devicename
, ALCuint frequency
,
865 ALCenum format
, ALCsizei buffersize
) noexcept
867 ALCdevice
*device
{nullptr};
870 if(devicename
&& *devicename
== '\0')
871 devicename
= nullptr;
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 %d for name \"%s\"\n", idx
, devicename
);
888 device
= DriverList
[idx
]->alcCaptureOpenDevice(devicename
, frequency
, format
, buffersize
);
892 for(const auto &drv
: DriverList
)
894 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
895 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
897 TRACE("Using default capture device from driver %d\n", idx
);
898 device
= drv
->alcCaptureOpenDevice(nullptr, frequency
, format
, buffersize
);
908 DeviceIfaceMap
.emplace(device
, idx
);
911 DriverList
[idx
]->alcCaptureCloseDevice(device
);
919 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
) noexcept
921 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
923 if(!DriverList
[*idx
]->alcCaptureCloseDevice(device
))
925 DeviceIfaceMap
.erase(device
);
929 LastError
.store(ALC_INVALID_DEVICE
);
933 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
) noexcept
935 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
936 return DriverList
[*idx
]->alcCaptureStart(device
);
937 LastError
.store(ALC_INVALID_DEVICE
);
940 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
) noexcept
942 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
943 return DriverList
[*idx
]->alcCaptureStop(device
);
944 LastError
.store(ALC_INVALID_DEVICE
);
947 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
) noexcept
949 if(const auto idx
= maybe_get(DeviceIfaceMap
, device
))
950 return DriverList
[*idx
]->alcCaptureSamples(device
, buffer
, samples
);
951 LastError
.store(ALC_INVALID_DEVICE
);
955 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
) noexcept
959 DriverIface
*oldiface
{GetThreadDriver()};
960 if(oldiface
&& !oldiface
->alcSetThreadContext(nullptr))
962 SetThreadDriver(nullptr);
966 ALCenum err
{ALC_INVALID_CONTEXT
};
967 if(const auto idx
= maybe_get(ContextIfaceMap
, context
).value_or(-1); idx
>= 0)
969 if(DriverList
[idx
]->alcSetThreadContext(context
))
971 std::call_once(DriverList
[idx
]->InitOnceCtx
, [idx
]{ InitCtxFuncs(*DriverList
[idx
]); });
973 DriverIface
*oldiface
{GetThreadDriver()};
974 if(oldiface
!= DriverList
[idx
].get())
976 SetThreadDriver(DriverList
[idx
].get());
977 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
981 err
= DriverList
[idx
]->alcGetError(nullptr);
983 LastError
.store(err
);
987 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext() noexcept
989 if(DriverIface
*iface
{GetThreadDriver()})
990 return iface
->alcGetThreadContext();