19 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
20 struct FuncExportEntry
{
24 static const std::array
<FuncExportEntry
,128> alcFunctions
{{
25 DECL(alcCreateContext
),
26 DECL(alcMakeContextCurrent
),
27 DECL(alcProcessContext
),
28 DECL(alcSuspendContext
),
29 DECL(alcDestroyContext
),
30 DECL(alcGetCurrentContext
),
31 DECL(alcGetContextsDevice
),
35 DECL(alcIsExtensionPresent
),
36 DECL(alcGetProcAddress
),
37 DECL(alcGetEnumValue
),
40 DECL(alcCaptureOpenDevice
),
41 DECL(alcCaptureCloseDevice
),
42 DECL(alcCaptureStart
),
44 DECL(alcCaptureSamples
),
46 DECL(alcSetThreadContext
),
47 DECL(alcGetThreadContext
),
62 DECL(alIsExtensionPresent
),
63 DECL(alGetProcAddress
),
72 DECL(alGetListener3f
),
73 DECL(alGetListenerfv
),
75 DECL(alGetListener3i
),
76 DECL(alGetListeneriv
),
78 DECL(alDeleteSources
),
94 DECL(alSourceRewindv
),
100 DECL(alSourceQueueBuffers
),
101 DECL(alSourceUnqueueBuffers
),
103 DECL(alDeleteBuffers
),
118 DECL(alDopplerFactor
),
119 DECL(alDopplerVelocity
),
120 DECL(alSpeedOfSound
),
121 DECL(alDistanceModel
),
125 DECL(alDeleteFilters
),
136 DECL(alDeleteEffects
),
146 DECL(alGenAuxiliaryEffectSlots
),
147 DECL(alDeleteAuxiliaryEffectSlots
),
148 DECL(alIsAuxiliaryEffectSlot
),
149 DECL(alAuxiliaryEffectSlotf
),
150 DECL(alAuxiliaryEffectSlotfv
),
151 DECL(alAuxiliaryEffectSloti
),
152 DECL(alAuxiliaryEffectSlotiv
),
153 DECL(alGetAuxiliaryEffectSlotf
),
154 DECL(alGetAuxiliaryEffectSlotfv
),
155 DECL(alGetAuxiliaryEffectSloti
),
156 DECL(alGetAuxiliaryEffectSlotiv
),
160 #define DECL(x) { #x, (x) }
161 struct EnumExportEntry
{
162 const ALCchar
*enumName
;
165 static const std::array
<EnumExportEntry
,92> alcEnumerations
{{
170 DECL(ALC_MAJOR_VERSION
),
171 DECL(ALC_MINOR_VERSION
),
172 DECL(ALC_ATTRIBUTES_SIZE
),
173 DECL(ALC_ALL_ATTRIBUTES
),
174 DECL(ALC_DEFAULT_DEVICE_SPECIFIER
),
175 DECL(ALC_DEVICE_SPECIFIER
),
176 DECL(ALC_ALL_DEVICES_SPECIFIER
),
177 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER
),
178 DECL(ALC_EXTENSIONS
),
182 DECL(ALC_MONO_SOURCES
),
183 DECL(ALC_STEREO_SOURCES
),
184 DECL(ALC_CAPTURE_DEVICE_SPECIFIER
),
185 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
),
186 DECL(ALC_CAPTURE_SAMPLES
),
189 DECL(ALC_INVALID_DEVICE
),
190 DECL(ALC_INVALID_CONTEXT
),
191 DECL(ALC_INVALID_ENUM
),
192 DECL(ALC_INVALID_VALUE
),
193 DECL(ALC_OUT_OF_MEMORY
),
200 DECL(AL_SOURCE_RELATIVE
),
201 DECL(AL_CONE_INNER_ANGLE
),
202 DECL(AL_CONE_OUTER_ANGLE
),
212 DECL(AL_ORIENTATION
),
213 DECL(AL_REFERENCE_DISTANCE
),
214 DECL(AL_ROLLOFF_FACTOR
),
215 DECL(AL_CONE_OUTER_GAIN
),
216 DECL(AL_MAX_DISTANCE
),
218 DECL(AL_SAMPLE_OFFSET
),
219 DECL(AL_BYTE_OFFSET
),
220 DECL(AL_SOURCE_TYPE
),
223 DECL(AL_UNDETERMINED
),
225 DECL(AL_SOURCE_STATE
),
231 DECL(AL_BUFFERS_QUEUED
),
232 DECL(AL_BUFFERS_PROCESSED
),
234 DECL(AL_FORMAT_MONO8
),
235 DECL(AL_FORMAT_MONO16
),
236 DECL(AL_FORMAT_STEREO8
),
237 DECL(AL_FORMAT_STEREO16
),
249 DECL(AL_INVALID_NAME
),
250 DECL(AL_INVALID_ENUM
),
251 DECL(AL_INVALID_VALUE
),
252 DECL(AL_INVALID_OPERATION
),
253 DECL(AL_OUT_OF_MEMORY
),
260 DECL(AL_DOPPLER_FACTOR
),
261 DECL(AL_DOPPLER_VELOCITY
),
262 DECL(AL_DISTANCE_MODEL
),
263 DECL(AL_SPEED_OF_SOUND
),
265 DECL(AL_INVERSE_DISTANCE
),
266 DECL(AL_INVERSE_DISTANCE_CLAMPED
),
267 DECL(AL_LINEAR_DISTANCE
),
268 DECL(AL_LINEAR_DISTANCE_CLAMPED
),
269 DECL(AL_EXPONENT_DISTANCE
),
270 DECL(AL_EXPONENT_DISTANCE_CLAMPED
),
274 static const ALCchar alcNoError
[] = "No Error";
275 static const ALCchar alcErrInvalidDevice
[] = "Invalid Device";
276 static const ALCchar alcErrInvalidContext
[] = "Invalid Context";
277 static const ALCchar alcErrInvalidEnum
[] = "Invalid Enum";
278 static const ALCchar alcErrInvalidValue
[] = "Invalid Value";
279 static const ALCchar alcErrOutOfMemory
[] = "Out of Memory";
280 static const ALCchar alcExtensionList
[] =
281 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
282 "ALC_EXT_thread_local_context";
284 static const ALCint alcMajorVersion
= 1;
285 static const ALCint alcMinorVersion
= 1;
288 static std::recursive_mutex EnumerationLock
;
289 static std::mutex ContextSwitchLock
;
291 static std::atomic
<ALCenum
> LastError
{ALC_NO_ERROR
};
292 static PtrIntMap DeviceIfaceMap
;
293 static PtrIntMap ContextIfaceMap
;
296 typedef struct EnumeratedList
{
297 std::vector
<ALCchar
> Names
;
298 std::vector
<ALCint
> Indicies
;
306 static EnumeratedList DevicesList
;
307 static EnumeratedList AllDevicesList
;
308 static EnumeratedList CaptureDevicesList
;
310 static void AppendDeviceList(EnumeratedList
*list
, const ALCchar
*names
, ALint idx
)
312 const ALCchar
*name_end
= names
;
313 if(!name_end
) return;
318 TRACE("Enumerated \"%s\", driver %d\n", name_end
, idx
);
320 name_end
+= strlen(name_end
)+1;
322 if(names
== name_end
)
325 list
->Names
.reserve(list
->Names
.size() + (name_end
- names
) + 1);
326 list
->Names
.insert(list
->Names
.cend(), names
, name_end
);
328 list
->Indicies
.reserve(list
->Indicies
.size() + count
);
329 list
->Indicies
.insert(list
->Indicies
.cend(), count
, idx
);
332 static ALint
GetDriverIndexForName(const EnumeratedList
*list
, const ALCchar
*name
)
334 const ALCchar
*devnames
= list
->Names
.data();
335 const ALCint
*index
= list
->Indicies
.data();
337 while(devnames
&& *devnames
)
339 if(strcmp(name
, devnames
) == 0)
341 devnames
+= strlen(devnames
)+1;
348 static void InitCtxFuncs(DriverIface
&iface
)
350 ALCdevice
*device
{iface
.alcGetContextsDevice(iface
.alcGetCurrentContext())};
352 #define LOAD_PROC(x) do { \
353 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
355 ERR("Failed to find entry point for %s in %ls\n", #x, \
356 iface.Name.c_str()); \
358 if(iface
.alcIsExtensionPresent(device
, "ALC_EXT_EFX"))
360 LOAD_PROC(alGenFilters
);
361 LOAD_PROC(alDeleteFilters
);
362 LOAD_PROC(alIsFilter
);
363 LOAD_PROC(alFilterf
);
364 LOAD_PROC(alFilterfv
);
365 LOAD_PROC(alFilteri
);
366 LOAD_PROC(alFilteriv
);
367 LOAD_PROC(alGetFilterf
);
368 LOAD_PROC(alGetFilterfv
);
369 LOAD_PROC(alGetFilteri
);
370 LOAD_PROC(alGetFilteriv
);
371 LOAD_PROC(alGenEffects
);
372 LOAD_PROC(alDeleteEffects
);
373 LOAD_PROC(alIsEffect
);
374 LOAD_PROC(alEffectf
);
375 LOAD_PROC(alEffectfv
);
376 LOAD_PROC(alEffecti
);
377 LOAD_PROC(alEffectiv
);
378 LOAD_PROC(alGetEffectf
);
379 LOAD_PROC(alGetEffectfv
);
380 LOAD_PROC(alGetEffecti
);
381 LOAD_PROC(alGetEffectiv
);
382 LOAD_PROC(alGenAuxiliaryEffectSlots
);
383 LOAD_PROC(alDeleteAuxiliaryEffectSlots
);
384 LOAD_PROC(alIsAuxiliaryEffectSlot
);
385 LOAD_PROC(alAuxiliaryEffectSlotf
);
386 LOAD_PROC(alAuxiliaryEffectSlotfv
);
387 LOAD_PROC(alAuxiliaryEffectSloti
);
388 LOAD_PROC(alAuxiliaryEffectSlotiv
);
389 LOAD_PROC(alGetAuxiliaryEffectSlotf
);
390 LOAD_PROC(alGetAuxiliaryEffectSlotfv
);
391 LOAD_PROC(alGetAuxiliaryEffectSloti
);
392 LOAD_PROC(alGetAuxiliaryEffectSlotiv
);
398 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*devicename
) noexcept
400 ALCdevice
*device
= nullptr;
403 /* Prior to the enumeration extension, apps would hardcode these names as a
404 * quality hint for the wrapper driver. Ignore them since there's no sane
407 if(devicename
&& (devicename
[0] == '\0' ||
408 strcmp(devicename
, "DirectSound3D") == 0 ||
409 strcmp(devicename
, "DirectSound") == 0 ||
410 strcmp(devicename
, "MMSYSTEM") == 0))
411 devicename
= nullptr;
415 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
416 if(DevicesList
.Names
.empty())
417 std::ignore
= alcGetString(nullptr, ALC_DEVICE_SPECIFIER
);
418 idx
= GetDriverIndexForName(&DevicesList
, devicename
);
421 if(AllDevicesList
.Names
.empty())
422 std::ignore
= alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
);
423 idx
= GetDriverIndexForName(&AllDevicesList
, devicename
);
429 LastError
.store(ALC_INVALID_VALUE
);
430 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
433 TRACE("Found driver %d for name \"%s\"\n", idx
, devicename
);
434 device
= DriverList
[idx
]->alcOpenDevice(devicename
);
438 for(const auto &drv
: DriverList
)
440 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
441 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
443 TRACE("Using default device from driver %d\n", idx
);
444 device
= drv
->alcOpenDevice(nullptr);
453 if(DeviceIfaceMap
.insert(device
, idx
) != ALC_NO_ERROR
)
455 DriverList
[idx
]->alcCloseDevice(device
);
463 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
) noexcept
467 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
469 LastError
.store(ALC_INVALID_DEVICE
);
472 if(!DriverList
[idx
]->alcCloseDevice(device
))
474 DeviceIfaceMap
.removeByKey(device
);
479 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrlist
) noexcept
484 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
486 LastError
.store(ALC_INVALID_DEVICE
);
489 context
= DriverList
[idx
]->alcCreateContext(device
, attrlist
);
492 if(ContextIfaceMap
.insert(context
, idx
) != ALC_NO_ERROR
)
494 DriverList
[idx
]->alcDestroyContext(context
);
502 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
) noexcept
506 std::lock_guard
<std::mutex
> ctxlock
{ContextSwitchLock
};
509 idx
= ContextIfaceMap
.lookupByKey(context
);
512 LastError
.store(ALC_INVALID_CONTEXT
);
515 if(!DriverList
[idx
]->alcMakeContextCurrent(context
))
518 auto do_init
= [idx
]() { InitCtxFuncs(*DriverList
[idx
]); };
519 std::call_once(DriverList
[idx
]->InitOnceCtx
, do_init
);
522 /* Unset the context from the old driver if it's different from the new
527 DriverIface
*oldiface
= GetThreadDriver();
528 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
529 oldiface
= CurrentCtxDriver
.exchange(nullptr);
530 if(oldiface
) oldiface
->alcMakeContextCurrent(nullptr);
534 DriverIface
*oldiface
= GetThreadDriver();
535 if(oldiface
&& oldiface
!= DriverList
[idx
].get())
536 oldiface
->alcSetThreadContext(nullptr);
537 oldiface
= CurrentCtxDriver
.exchange(DriverList
[idx
].get());
538 if(oldiface
&& oldiface
!= DriverList
[idx
].get())
539 oldiface
->alcMakeContextCurrent(nullptr);
541 SetThreadDriver(nullptr);
546 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
) noexcept
550 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
552 return DriverList
[idx
]->alcProcessContext(context
);
554 LastError
.store(ALC_INVALID_CONTEXT
);
557 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
) noexcept
561 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
563 return DriverList
[idx
]->alcSuspendContext(context
);
565 LastError
.store(ALC_INVALID_CONTEXT
);
568 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
) noexcept
572 if(!context
|| (idx
=ContextIfaceMap
.lookupByKey(context
)) < 0)
574 LastError
.store(ALC_INVALID_CONTEXT
);
578 DriverList
[idx
]->alcDestroyContext(context
);
579 ContextIfaceMap
.removeByKey(context
);
582 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext() noexcept
584 DriverIface
*iface
= GetThreadDriver();
585 if(!iface
) iface
= CurrentCtxDriver
.load();
586 return iface
? iface
->alcGetCurrentContext() : nullptr;
589 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*context
) noexcept
593 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
595 return DriverList
[idx
]->alcGetContextsDevice(context
);
597 LastError
.store(ALC_INVALID_CONTEXT
);
602 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
) noexcept
606 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
607 if(idx
< 0) return ALC_INVALID_DEVICE
;
608 return DriverList
[idx
]->alcGetError(device
);
610 return LastError
.exchange(ALC_NO_ERROR
);
613 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extname
) noexcept
620 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
623 LastError
.store(ALC_INVALID_DEVICE
);
626 return DriverList
[idx
]->alcIsExtensionPresent(device
, extname
);
629 len
= strlen(extname
);
630 ptr
= alcExtensionList
;
633 if(al::strncasecmp(ptr
, extname
, len
) == 0 && (ptr
[len
] == '\0' || isspace(ptr
[len
])))
635 if((ptr
=strchr(ptr
, ' ')) != nullptr)
639 } while(isspace(*ptr
));
645 ALC_API
void* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcname
) noexcept
649 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
652 LastError
.store(ALC_INVALID_DEVICE
);
655 return DriverList
[idx
]->alcGetProcAddress(device
, funcname
);
658 auto iter
= std::find_if(alcFunctions
.cbegin(), alcFunctions
.cend(),
659 [funcname
](const FuncExportEntry
&entry
) -> bool
660 { return strcmp(funcname
, entry
.funcName
) == 0; }
662 return (iter
!= alcFunctions
.cend()) ? iter
->address
: nullptr;
665 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumname
) noexcept
669 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
672 LastError
.store(ALC_INVALID_DEVICE
);
675 return DriverList
[idx
]->alcGetEnumValue(device
, enumname
);
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 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
692 LastError
.store(ALC_INVALID_DEVICE
);
695 return DriverList
[idx
]->alcGetString(device
, param
);
702 case ALC_INVALID_ENUM
:
703 return alcErrInvalidEnum
;
704 case ALC_INVALID_VALUE
:
705 return alcErrInvalidValue
;
706 case ALC_INVALID_DEVICE
:
707 return alcErrInvalidDevice
;
708 case ALC_INVALID_CONTEXT
:
709 return alcErrInvalidContext
;
710 case ALC_OUT_OF_MEMORY
:
711 return alcErrOutOfMemory
;
713 return alcExtensionList
;
715 case ALC_DEVICE_SPECIFIER
:
717 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
720 for(const auto &drv
: DriverList
)
722 /* Only enumerate names from drivers that support it. */
723 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
724 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
725 AppendDeviceList(&DevicesList
,
726 drv
->alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
729 /* Ensure the list is double-null termianted. */
730 if(DevicesList
.Names
.empty())
731 DevicesList
.Names
.emplace_back('\0');
732 DevicesList
.Names
.emplace_back('\0');
733 return DevicesList
.Names
.data();
736 case ALC_ALL_DEVICES_SPECIFIER
:
738 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
739 AllDevicesList
.clear();
741 for(const auto &drv
: DriverList
)
743 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
744 * standard enumeration.
746 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
747 AppendDeviceList(&AllDevicesList
,
748 drv
->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
), idx
);
749 else if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
750 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
751 AppendDeviceList(&AllDevicesList
,
752 drv
->alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
755 /* Ensure the list is double-null termianted. */
756 if(AllDevicesList
.Names
.empty())
757 AllDevicesList
.Names
.emplace_back('\0');
758 AllDevicesList
.Names
.emplace_back('\0');
759 return AllDevicesList
.Names
.data();
762 case ALC_CAPTURE_DEVICE_SPECIFIER
:
764 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
765 CaptureDevicesList
.clear();
767 for(const auto &drv
: DriverList
)
769 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
770 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
771 AppendDeviceList(&CaptureDevicesList
,
772 drv
->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
), idx
);
775 /* Ensure the list is double-null termianted. */
776 if(CaptureDevicesList
.Names
.empty())
777 CaptureDevicesList
.Names
.emplace_back('\0');
778 CaptureDevicesList
.Names
.emplace_back('\0');
779 return CaptureDevicesList
.Names
.data();
782 case ALC_DEFAULT_DEVICE_SPECIFIER
:
784 for(const auto &drv
: DriverList
)
786 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
787 || drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
788 return drv
->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER
);
793 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
795 for(const auto &drv
: DriverList
)
797 if(drv
->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE
)
798 return drv
->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER
);
803 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
805 for(const auto &drv
: DriverList
)
807 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
808 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
809 return drv
->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
);
815 LastError
.store(ALC_INVALID_ENUM
);
821 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
) noexcept
825 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
828 LastError
.store(ALC_INVALID_DEVICE
);
831 return DriverList
[idx
]->alcGetIntegerv(device
, param
, size
, values
);
834 if(size
<= 0 || values
== nullptr)
836 LastError
.store(ALC_INVALID_VALUE
);
842 case ALC_MAJOR_VERSION
:
845 values
[0] = alcMajorVersion
;
849 case ALC_MINOR_VERSION
:
852 values
[0] = alcMinorVersion
;
855 LastError
.store(ALC_INVALID_VALUE
);
858 case ALC_ATTRIBUTES_SIZE
:
859 case ALC_ALL_ATTRIBUTES
:
863 case ALC_MONO_SOURCES
:
864 case ALC_STEREO_SOURCES
:
865 case ALC_CAPTURE_SAMPLES
:
866 LastError
.store(ALC_INVALID_DEVICE
);
870 LastError
.store(ALC_INVALID_ENUM
);
876 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*devicename
, ALCuint frequency
, ALCenum format
, ALCsizei buffersize
) noexcept
878 ALCdevice
*device
= nullptr;
881 if(devicename
&& devicename
[0] == '\0')
882 devicename
= nullptr;
886 std::lock_guard
<std::recursive_mutex
> enumlock
{EnumerationLock
};
887 if(CaptureDevicesList
.Names
.empty())
888 std::ignore
= alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
);
889 idx
= GetDriverIndexForName(&CaptureDevicesList
, devicename
);
894 LastError
.store(ALC_INVALID_VALUE
);
895 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
898 TRACE("Found driver %d for name \"%s\"\n", idx
, devicename
);
899 device
= DriverList
[idx
]->alcCaptureOpenDevice(devicename
, frequency
, format
, buffersize
);
903 for(const auto &drv
: DriverList
)
905 if(drv
->ALCVer
>= MAKE_ALC_VER(1, 1)
906 || drv
->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
908 TRACE("Using default capture device from driver %d\n", idx
);
909 device
= drv
->alcCaptureOpenDevice(nullptr, frequency
, format
, buffersize
);
918 if(DeviceIfaceMap
.insert(device
, idx
) != ALC_NO_ERROR
)
920 DriverList
[idx
]->alcCaptureCloseDevice(device
);
928 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
) noexcept
932 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
934 LastError
.store(ALC_INVALID_DEVICE
);
937 if(!DriverList
[idx
]->alcCaptureCloseDevice(device
))
939 DeviceIfaceMap
.removeByKey(device
);
943 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
) noexcept
947 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
949 return DriverList
[idx
]->alcCaptureStart(device
);
951 LastError
.store(ALC_INVALID_DEVICE
);
954 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
) noexcept
958 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
960 return DriverList
[idx
]->alcCaptureStop(device
);
962 LastError
.store(ALC_INVALID_DEVICE
);
965 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
) noexcept
969 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
971 return DriverList
[idx
]->alcCaptureSamples(device
, buffer
, samples
);
973 LastError
.store(ALC_INVALID_DEVICE
);
977 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
) noexcept
979 ALCenum err
= ALC_INVALID_CONTEXT
;
984 DriverIface
*oldiface
= GetThreadDriver();
985 if(oldiface
&& !oldiface
->alcSetThreadContext(nullptr))
987 SetThreadDriver(nullptr);
991 idx
= ContextIfaceMap
.lookupByKey(context
);
994 if(DriverList
[idx
]->alcSetThreadContext(context
))
996 auto do_init
= [idx
]() { InitCtxFuncs(*DriverList
[idx
]); };
997 std::call_once(DriverList
[idx
]->InitOnceCtx
, do_init
);
999 DriverIface
*oldiface
= GetThreadDriver();
1000 if(oldiface
!= DriverList
[idx
].get())
1002 SetThreadDriver(DriverList
[idx
].get());
1003 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
1007 err
= DriverList
[idx
]->alcGetError(nullptr);
1009 LastError
.store(err
);
1013 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext() noexcept
1015 DriverIface
*iface
= GetThreadDriver();
1016 if(iface
) return iface
->alcGetThreadContext();