18 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
19 struct FuncExportEntry
{
23 static const std::array
<FuncExportEntry
,128> alcFunctions
{{
24 DECL(alcCreateContext
),
25 DECL(alcMakeContextCurrent
),
26 DECL(alcProcessContext
),
27 DECL(alcSuspendContext
),
28 DECL(alcDestroyContext
),
29 DECL(alcGetCurrentContext
),
30 DECL(alcGetContextsDevice
),
34 DECL(alcIsExtensionPresent
),
35 DECL(alcGetProcAddress
),
36 DECL(alcGetEnumValue
),
39 DECL(alcCaptureOpenDevice
),
40 DECL(alcCaptureCloseDevice
),
41 DECL(alcCaptureStart
),
43 DECL(alcCaptureSamples
),
45 DECL(alcSetThreadContext
),
46 DECL(alcGetThreadContext
),
61 DECL(alIsExtensionPresent
),
62 DECL(alGetProcAddress
),
71 DECL(alGetListener3f
),
72 DECL(alGetListenerfv
),
74 DECL(alGetListener3i
),
75 DECL(alGetListeneriv
),
77 DECL(alDeleteSources
),
93 DECL(alSourceRewindv
),
99 DECL(alSourceQueueBuffers
),
100 DECL(alSourceUnqueueBuffers
),
102 DECL(alDeleteBuffers
),
117 DECL(alDopplerFactor
),
118 DECL(alDopplerVelocity
),
119 DECL(alSpeedOfSound
),
120 DECL(alDistanceModel
),
124 #define DECL(x) { #x, (x) }
125 struct EnumExportEntry
{
126 const ALCchar
*enumName
;
129 static const std::array
<EnumExportEntry
,92> alcEnumerations
{{
134 DECL(ALC_MAJOR_VERSION
),
135 DECL(ALC_MINOR_VERSION
),
136 DECL(ALC_ATTRIBUTES_SIZE
),
137 DECL(ALC_ALL_ATTRIBUTES
),
138 DECL(ALC_DEFAULT_DEVICE_SPECIFIER
),
139 DECL(ALC_DEVICE_SPECIFIER
),
140 DECL(ALC_ALL_DEVICES_SPECIFIER
),
141 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER
),
142 DECL(ALC_EXTENSIONS
),
146 DECL(ALC_MONO_SOURCES
),
147 DECL(ALC_STEREO_SOURCES
),
148 DECL(ALC_CAPTURE_DEVICE_SPECIFIER
),
149 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
),
150 DECL(ALC_CAPTURE_SAMPLES
),
153 DECL(ALC_INVALID_DEVICE
),
154 DECL(ALC_INVALID_CONTEXT
),
155 DECL(ALC_INVALID_ENUM
),
156 DECL(ALC_INVALID_VALUE
),
157 DECL(ALC_OUT_OF_MEMORY
),
164 DECL(AL_SOURCE_RELATIVE
),
165 DECL(AL_CONE_INNER_ANGLE
),
166 DECL(AL_CONE_OUTER_ANGLE
),
176 DECL(AL_ORIENTATION
),
177 DECL(AL_REFERENCE_DISTANCE
),
178 DECL(AL_ROLLOFF_FACTOR
),
179 DECL(AL_CONE_OUTER_GAIN
),
180 DECL(AL_MAX_DISTANCE
),
182 DECL(AL_SAMPLE_OFFSET
),
183 DECL(AL_BYTE_OFFSET
),
184 DECL(AL_SOURCE_TYPE
),
187 DECL(AL_UNDETERMINED
),
189 DECL(AL_SOURCE_STATE
),
195 DECL(AL_BUFFERS_QUEUED
),
196 DECL(AL_BUFFERS_PROCESSED
),
198 DECL(AL_FORMAT_MONO8
),
199 DECL(AL_FORMAT_MONO16
),
200 DECL(AL_FORMAT_STEREO8
),
201 DECL(AL_FORMAT_STEREO16
),
213 DECL(AL_INVALID_NAME
),
214 DECL(AL_INVALID_ENUM
),
215 DECL(AL_INVALID_VALUE
),
216 DECL(AL_INVALID_OPERATION
),
217 DECL(AL_OUT_OF_MEMORY
),
224 DECL(AL_DOPPLER_FACTOR
),
225 DECL(AL_DOPPLER_VELOCITY
),
226 DECL(AL_DISTANCE_MODEL
),
227 DECL(AL_SPEED_OF_SOUND
),
229 DECL(AL_INVERSE_DISTANCE
),
230 DECL(AL_INVERSE_DISTANCE_CLAMPED
),
231 DECL(AL_LINEAR_DISTANCE
),
232 DECL(AL_LINEAR_DISTANCE_CLAMPED
),
233 DECL(AL_EXPONENT_DISTANCE
),
234 DECL(AL_EXPONENT_DISTANCE_CLAMPED
),
238 static const ALCchar alcNoError
[] = "No Error";
239 static const ALCchar alcErrInvalidDevice
[] = "Invalid Device";
240 static const ALCchar alcErrInvalidContext
[] = "Invalid Context";
241 static const ALCchar alcErrInvalidEnum
[] = "Invalid Enum";
242 static const ALCchar alcErrInvalidValue
[] = "Invalid Value";
243 static const ALCchar alcErrOutOfMemory
[] = "Out of Memory";
244 static const ALCchar alcExtensionList
[] =
245 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
246 "ALC_EXT_thread_local_context";
248 static const ALCint alcMajorVersion
= 1;
249 static const ALCint alcMinorVersion
= 1;
252 static std::recursive_mutex EnumerationLock
;
253 static std::mutex ContextSwitchLock
;
255 static std::atomic
<ALCenum
> LastError
{ALC_NO_ERROR
};
256 static PtrIntMap DeviceIfaceMap
;
257 static PtrIntMap ContextIfaceMap
;
260 typedef struct EnumeratedList
{
261 std::vector
<ALCchar
> Names
;
262 std::vector
<ALCint
> Indicies
;
270 static EnumeratedList DevicesList
;
271 static EnumeratedList AllDevicesList
;
272 static EnumeratedList CaptureDevicesList
;
274 static void AppendDeviceList(EnumeratedList
*list
, const ALCchar
*names
, ALint idx
)
276 const ALCchar
*name_end
= names
;
277 if(!name_end
) return;
282 TRACE("Enumerated \"%s\", driver %d\n", name_end
, idx
);
284 name_end
+= strlen(name_end
)+1;
286 if(names
== name_end
)
289 list
->Names
.reserve(list
->Names
.size() + (name_end
- names
) + 1);
290 list
->Names
.insert(list
->Names
.cend(), names
, name_end
);
292 list
->Indicies
.reserve(list
->Indicies
.size() + count
);
293 list
->Indicies
.insert(list
->Indicies
.cend(), count
, idx
);
296 static ALint
GetDriverIndexForName(const EnumeratedList
*list
, const ALCchar
*name
)
298 const ALCchar
*devnames
= list
->Names
.data();
299 const ALCint
*index
= list
->Indicies
.data();
301 while(devnames
&& *devnames
)
303 if(strcmp(name
, devnames
) == 0)
305 devnames
+= strlen(devnames
)+1;
312 ALC_API ALCdevice
* ALC_APIENTRY
alcOpenDevice(const ALCchar
*devicename
)
314 ALCdevice
*device
= nullptr;
317 /* Prior to the enumeration extension, apps would hardcode these names as a
318 * quality hint for the wrapper driver. Ignore them since there's no sane
321 if(devicename
&& (devicename
[0] == '\0' ||
322 strcmp(devicename
, "DirectSound3D") == 0 ||
323 strcmp(devicename
, "DirectSound") == 0 ||
324 strcmp(devicename
, "MMSYSTEM") == 0))
325 devicename
= nullptr;
329 std::lock_guard
<std::recursive_mutex
> _
{EnumerationLock
};
330 if(DevicesList
.Names
.empty())
331 (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER
);
332 idx
= GetDriverIndexForName(&DevicesList
, devicename
);
335 if(AllDevicesList
.Names
.empty())
336 (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
);
337 idx
= GetDriverIndexForName(&AllDevicesList
, devicename
);
343 LastError
.store(ALC_INVALID_VALUE
);
344 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
347 TRACE("Found driver %d for name \"%s\"\n", idx
, devicename
);
348 device
= DriverList
[idx
].alcOpenDevice(devicename
);
352 for(const auto &drv
: DriverList
)
354 if(drv
.ALCVer
>= MAKE_ALC_VER(1, 1) ||
355 drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
357 TRACE("Using default device from driver %d\n", idx
);
358 device
= drv
.alcOpenDevice(nullptr);
367 if(DeviceIfaceMap
.insert(device
, idx
) != ALC_NO_ERROR
)
369 DriverList
[idx
].alcCloseDevice(device
);
377 ALC_API ALCboolean ALC_APIENTRY
alcCloseDevice(ALCdevice
*device
)
381 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
383 LastError
.store(ALC_INVALID_DEVICE
);
386 if(!DriverList
[idx
].alcCloseDevice(device
))
388 DeviceIfaceMap
.removeByKey(device
);
393 ALC_API ALCcontext
* ALC_APIENTRY
alcCreateContext(ALCdevice
*device
, const ALCint
*attrlist
)
398 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
400 LastError
.store(ALC_INVALID_DEVICE
);
403 context
= DriverList
[idx
].alcCreateContext(device
, attrlist
);
406 if(ContextIfaceMap
.insert(context
, idx
) != ALC_NO_ERROR
)
408 DriverList
[idx
].alcDestroyContext(context
);
416 ALC_API ALCboolean ALC_APIENTRY
alcMakeContextCurrent(ALCcontext
*context
)
420 std::lock_guard
<std::mutex
> _
{ContextSwitchLock
};
423 idx
= ContextIfaceMap
.lookupByKey(context
);
426 LastError
.store(ALC_INVALID_CONTEXT
);
429 if(!DriverList
[idx
].alcMakeContextCurrent(context
))
433 /* Unset the context from the old driver if it's different from the new
438 DriverIface
*oldiface
= GetThreadDriver();
439 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
440 oldiface
= CurrentCtxDriver
.exchange(nullptr);
441 if(oldiface
) oldiface
->alcMakeContextCurrent(nullptr);
445 DriverIface
*oldiface
= GetThreadDriver();
446 if(oldiface
&& oldiface
!= &DriverList
[idx
])
447 oldiface
->alcSetThreadContext(nullptr);
448 oldiface
= CurrentCtxDriver
.exchange(&DriverList
[idx
]);
449 if(oldiface
&& oldiface
!= &DriverList
[idx
])
450 oldiface
->alcMakeContextCurrent(nullptr);
452 SetThreadDriver(nullptr);
457 ALC_API
void ALC_APIENTRY
alcProcessContext(ALCcontext
*context
)
461 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
463 return DriverList
[idx
].alcProcessContext(context
);
465 LastError
.store(ALC_INVALID_CONTEXT
);
468 ALC_API
void ALC_APIENTRY
alcSuspendContext(ALCcontext
*context
)
472 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
474 return DriverList
[idx
].alcSuspendContext(context
);
476 LastError
.store(ALC_INVALID_CONTEXT
);
479 ALC_API
void ALC_APIENTRY
alcDestroyContext(ALCcontext
*context
)
483 if(!context
|| (idx
=ContextIfaceMap
.lookupByKey(context
)) < 0)
485 LastError
.store(ALC_INVALID_CONTEXT
);
489 DriverList
[idx
].alcDestroyContext(context
);
490 ContextIfaceMap
.removeByKey(context
);
493 ALC_API ALCcontext
* ALC_APIENTRY
alcGetCurrentContext(void)
495 DriverIface
*iface
= GetThreadDriver();
496 if(!iface
) iface
= CurrentCtxDriver
.load();
497 return iface
? iface
->alcGetCurrentContext() : nullptr;
500 ALC_API ALCdevice
* ALC_APIENTRY
alcGetContextsDevice(ALCcontext
*context
)
504 ALint idx
= ContextIfaceMap
.lookupByKey(context
);
506 return DriverList
[idx
].alcGetContextsDevice(context
);
508 LastError
.store(ALC_INVALID_CONTEXT
);
513 ALC_API ALCenum ALC_APIENTRY
alcGetError(ALCdevice
*device
)
517 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
518 if(idx
< 0) return ALC_INVALID_DEVICE
;
519 return DriverList
[idx
].alcGetError(device
);
521 return LastError
.exchange(ALC_NO_ERROR
);
524 ALC_API ALCboolean ALC_APIENTRY
alcIsExtensionPresent(ALCdevice
*device
, const ALCchar
*extname
)
531 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
534 LastError
.store(ALC_INVALID_DEVICE
);
537 return DriverList
[idx
].alcIsExtensionPresent(device
, extname
);
540 len
= strlen(extname
);
541 ptr
= alcExtensionList
;
544 if(al::strncasecmp(ptr
, extname
, len
) == 0 && (ptr
[len
] == '\0' || isspace(ptr
[len
])))
546 if((ptr
=strchr(ptr
, ' ')) != nullptr)
550 } while(isspace(*ptr
));
556 ALC_API
void* ALC_APIENTRY
alcGetProcAddress(ALCdevice
*device
, const ALCchar
*funcname
)
560 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
563 LastError
.store(ALC_INVALID_DEVICE
);
566 return DriverList
[idx
].alcGetProcAddress(device
, funcname
);
569 auto iter
= std::find_if(alcFunctions
.cbegin(), alcFunctions
.cend(),
570 [funcname
](const FuncExportEntry
&entry
) -> bool
571 { return strcmp(funcname
, entry
.funcName
) == 0; }
573 return (iter
!= alcFunctions
.cend()) ? iter
->address
: nullptr;
576 ALC_API ALCenum ALC_APIENTRY
alcGetEnumValue(ALCdevice
*device
, const ALCchar
*enumname
)
580 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
583 LastError
.store(ALC_INVALID_DEVICE
);
586 return DriverList
[idx
].alcGetEnumValue(device
, enumname
);
589 auto iter
= std::find_if(alcEnumerations
.cbegin(), alcEnumerations
.cend(),
590 [enumname
](const EnumExportEntry
&entry
) -> bool
591 { return strcmp(enumname
, entry
.enumName
) == 0; }
593 return (iter
!= alcEnumerations
.cend()) ? iter
->value
: 0;
596 ALC_API
const ALCchar
* ALC_APIENTRY
alcGetString(ALCdevice
*device
, ALCenum param
)
600 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
603 LastError
.store(ALC_INVALID_DEVICE
);
606 return DriverList
[idx
].alcGetString(device
, param
);
613 case ALC_INVALID_ENUM
:
614 return alcErrInvalidEnum
;
615 case ALC_INVALID_VALUE
:
616 return alcErrInvalidValue
;
617 case ALC_INVALID_DEVICE
:
618 return alcErrInvalidDevice
;
619 case ALC_INVALID_CONTEXT
:
620 return alcErrInvalidContext
;
621 case ALC_OUT_OF_MEMORY
:
622 return alcErrOutOfMemory
;
624 return alcExtensionList
;
626 case ALC_DEVICE_SPECIFIER
:
628 std::lock_guard
<std::recursive_mutex
> _
{EnumerationLock
};
631 for(const auto &drv
: DriverList
)
633 /* Only enumerate names from drivers that support it. */
634 if(drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
635 || drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
636 AppendDeviceList(&DevicesList
,
637 drv
.alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
640 /* Ensure the list is double-null termianted. */
641 if(DevicesList
.Names
.empty())
642 DevicesList
.Names
.emplace_back('\0');
643 DevicesList
.Names
.emplace_back('\0');
644 return DevicesList
.Names
.data();
647 case ALC_ALL_DEVICES_SPECIFIER
:
649 std::lock_guard
<std::recursive_mutex
> _
{EnumerationLock
};
650 AllDevicesList
.clear();
652 for(const auto &drv
: DriverList
)
654 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
655 * standard enumeration.
657 if(drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
658 AppendDeviceList(&AllDevicesList
,
659 drv
.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER
), idx
);
660 else if(drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
661 || drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
662 AppendDeviceList(&AllDevicesList
,
663 drv
.alcGetString(nullptr, ALC_DEVICE_SPECIFIER
), idx
);
666 /* Ensure the list is double-null termianted. */
667 if(AllDevicesList
.Names
.empty())
668 AllDevicesList
.Names
.emplace_back('\0');
669 AllDevicesList
.Names
.emplace_back('\0');
670 return AllDevicesList
.Names
.data();
673 case ALC_CAPTURE_DEVICE_SPECIFIER
:
675 std::lock_guard
<std::recursive_mutex
> _
{EnumerationLock
};
676 CaptureDevicesList
.clear();
678 for(const auto &drv
: DriverList
)
680 if(drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
681 || drv
.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
682 AppendDeviceList(&CaptureDevicesList
,
683 drv
.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
), idx
);
686 /* Ensure the list is double-null termianted. */
687 if(CaptureDevicesList
.Names
.empty())
688 CaptureDevicesList
.Names
.emplace_back('\0');
689 CaptureDevicesList
.Names
.emplace_back('\0');
690 return CaptureDevicesList
.Names
.data();
693 case ALC_DEFAULT_DEVICE_SPECIFIER
:
695 auto iter
= std::find_if(DriverList
.cbegin(), DriverList
.cend(),
696 [](const DriverIface
&drv
) -> bool
698 return drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
699 || drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT");
702 if(iter
!= DriverList
.cend())
703 return iter
->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER
);
707 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER
:
709 auto iter
= std::find_if(DriverList
.cbegin(), DriverList
.cend(),
710 [](const DriverIface
&drv
) -> bool
711 { return drv
.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE
; });
712 if(iter
!= DriverList
.cend())
713 return iter
->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER
);
717 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
:
719 auto iter
= std::find_if(DriverList
.cbegin(), DriverList
.cend(),
720 [](const DriverIface
&drv
) -> bool
722 return drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
723 || drv
.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
726 if(iter
!= DriverList
.cend())
727 return iter
->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER
);
732 LastError
.store(ALC_INVALID_ENUM
);
738 ALC_API
void ALC_APIENTRY
alcGetIntegerv(ALCdevice
*device
, ALCenum param
, ALCsizei size
, ALCint
*values
)
742 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
745 LastError
.store(ALC_INVALID_DEVICE
);
748 return DriverList
[idx
].alcGetIntegerv(device
, param
, size
, values
);
751 if(size
<= 0 || values
== nullptr)
753 LastError
.store(ALC_INVALID_VALUE
);
759 case ALC_MAJOR_VERSION
:
762 values
[0] = alcMajorVersion
;
766 case ALC_MINOR_VERSION
:
769 values
[0] = alcMinorVersion
;
772 LastError
.store(ALC_INVALID_VALUE
);
775 case ALC_ATTRIBUTES_SIZE
:
776 case ALC_ALL_ATTRIBUTES
:
780 case ALC_MONO_SOURCES
:
781 case ALC_STEREO_SOURCES
:
782 case ALC_CAPTURE_SAMPLES
:
783 LastError
.store(ALC_INVALID_DEVICE
);
787 LastError
.store(ALC_INVALID_ENUM
);
793 ALC_API ALCdevice
* ALC_APIENTRY
alcCaptureOpenDevice(const ALCchar
*devicename
, ALCuint frequency
, ALCenum format
, ALCsizei buffersize
)
795 ALCdevice
*device
= nullptr;
798 if(devicename
&& devicename
[0] == '\0')
799 devicename
= nullptr;
803 std::lock_guard
<std::recursive_mutex
> _
{EnumerationLock
};
804 if(CaptureDevicesList
.Names
.empty())
805 (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER
);
806 idx
= GetDriverIndexForName(&CaptureDevicesList
, devicename
);
811 LastError
.store(ALC_INVALID_VALUE
);
812 TRACE("Failed to find driver for name \"%s\"\n", devicename
);
815 TRACE("Found driver %d for name \"%s\"\n", idx
, devicename
);
816 device
= DriverList
[idx
].alcCaptureOpenDevice(devicename
, frequency
, format
, buffersize
);
820 for(const auto &drv
: DriverList
)
822 if(drv
.ALCVer
>= MAKE_ALC_VER(1, 1)
823 || drv
.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
825 TRACE("Using default capture device from driver %d\n", idx
);
826 device
= drv
.alcCaptureOpenDevice(nullptr, frequency
, format
, buffersize
);
835 if(DeviceIfaceMap
.insert(device
, idx
) != ALC_NO_ERROR
)
837 DriverList
[idx
].alcCaptureCloseDevice(device
);
845 ALC_API ALCboolean ALC_APIENTRY
alcCaptureCloseDevice(ALCdevice
*device
)
849 if(!device
|| (idx
=DeviceIfaceMap
.lookupByKey(device
)) < 0)
851 LastError
.store(ALC_INVALID_DEVICE
);
854 if(!DriverList
[idx
].alcCaptureCloseDevice(device
))
856 DeviceIfaceMap
.removeByKey(device
);
860 ALC_API
void ALC_APIENTRY
alcCaptureStart(ALCdevice
*device
)
864 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
866 return DriverList
[idx
].alcCaptureStart(device
);
868 LastError
.store(ALC_INVALID_DEVICE
);
871 ALC_API
void ALC_APIENTRY
alcCaptureStop(ALCdevice
*device
)
875 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
877 return DriverList
[idx
].alcCaptureStop(device
);
879 LastError
.store(ALC_INVALID_DEVICE
);
882 ALC_API
void ALC_APIENTRY
alcCaptureSamples(ALCdevice
*device
, ALCvoid
*buffer
, ALCsizei samples
)
886 ALint idx
= DeviceIfaceMap
.lookupByKey(device
);
888 return DriverList
[idx
].alcCaptureSamples(device
, buffer
, samples
);
890 LastError
.store(ALC_INVALID_DEVICE
);
894 ALC_API ALCboolean ALC_APIENTRY
alcSetThreadContext(ALCcontext
*context
)
896 ALCenum err
= ALC_INVALID_CONTEXT
;
901 DriverIface
*oldiface
= GetThreadDriver();
902 if(oldiface
&& !oldiface
->alcSetThreadContext(nullptr))
904 SetThreadDriver(nullptr);
908 idx
= ContextIfaceMap
.lookupByKey(context
);
911 if(DriverList
[idx
].alcSetThreadContext(context
))
913 DriverIface
*oldiface
= GetThreadDriver();
914 if(oldiface
!= &DriverList
[idx
])
916 SetThreadDriver(&DriverList
[idx
]);
917 if(oldiface
) oldiface
->alcSetThreadContext(nullptr);
921 err
= DriverList
[idx
].alcGetError(nullptr);
923 LastError
.store(err
);
927 ALC_API ALCcontext
* ALC_APIENTRY
alcGetThreadContext(void)
929 DriverIface
*iface
= GetThreadDriver();
930 if(iface
) return iface
->alcGetThreadContext();