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 DECL(alDeleteFilters),
135 DECL(alDeleteEffects),
145 DECL(alGenAuxiliaryEffectSlots),
146 DECL(alDeleteAuxiliaryEffectSlots),
147 DECL(alIsAuxiliaryEffectSlot),
148 DECL(alAuxiliaryEffectSlotf),
149 DECL(alAuxiliaryEffectSlotfv),
150 DECL(alAuxiliaryEffectSloti),
151 DECL(alAuxiliaryEffectSlotiv),
152 DECL(alGetAuxiliaryEffectSlotf),
153 DECL(alGetAuxiliaryEffectSlotfv),
154 DECL(alGetAuxiliaryEffectSloti),
155 DECL(alGetAuxiliaryEffectSlotiv),
159 #define DECL(x) { #x, (x) }
160 struct EnumExportEntry {
161 const ALCchar *enumName;
164 static const std::array<EnumExportEntry,92> alcEnumerations{{
169 DECL(ALC_MAJOR_VERSION),
170 DECL(ALC_MINOR_VERSION),
171 DECL(ALC_ATTRIBUTES_SIZE),
172 DECL(ALC_ALL_ATTRIBUTES),
173 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
174 DECL(ALC_DEVICE_SPECIFIER),
175 DECL(ALC_ALL_DEVICES_SPECIFIER),
176 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
177 DECL(ALC_EXTENSIONS),
181 DECL(ALC_MONO_SOURCES),
182 DECL(ALC_STEREO_SOURCES),
183 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
184 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
185 DECL(ALC_CAPTURE_SAMPLES),
188 DECL(ALC_INVALID_DEVICE),
189 DECL(ALC_INVALID_CONTEXT),
190 DECL(ALC_INVALID_ENUM),
191 DECL(ALC_INVALID_VALUE),
192 DECL(ALC_OUT_OF_MEMORY),
199 DECL(AL_SOURCE_RELATIVE),
200 DECL(AL_CONE_INNER_ANGLE),
201 DECL(AL_CONE_OUTER_ANGLE),
211 DECL(AL_ORIENTATION),
212 DECL(AL_REFERENCE_DISTANCE),
213 DECL(AL_ROLLOFF_FACTOR),
214 DECL(AL_CONE_OUTER_GAIN),
215 DECL(AL_MAX_DISTANCE),
217 DECL(AL_SAMPLE_OFFSET),
218 DECL(AL_BYTE_OFFSET),
219 DECL(AL_SOURCE_TYPE),
222 DECL(AL_UNDETERMINED),
224 DECL(AL_SOURCE_STATE),
230 DECL(AL_BUFFERS_QUEUED),
231 DECL(AL_BUFFERS_PROCESSED),
233 DECL(AL_FORMAT_MONO8),
234 DECL(AL_FORMAT_MONO16),
235 DECL(AL_FORMAT_STEREO8),
236 DECL(AL_FORMAT_STEREO16),
248 DECL(AL_INVALID_NAME),
249 DECL(AL_INVALID_ENUM),
250 DECL(AL_INVALID_VALUE),
251 DECL(AL_INVALID_OPERATION),
252 DECL(AL_OUT_OF_MEMORY),
259 DECL(AL_DOPPLER_FACTOR),
260 DECL(AL_DOPPLER_VELOCITY),
261 DECL(AL_DISTANCE_MODEL),
262 DECL(AL_SPEED_OF_SOUND),
264 DECL(AL_INVERSE_DISTANCE),
265 DECL(AL_INVERSE_DISTANCE_CLAMPED),
266 DECL(AL_LINEAR_DISTANCE),
267 DECL(AL_LINEAR_DISTANCE_CLAMPED),
268 DECL(AL_EXPONENT_DISTANCE),
269 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
273 static const ALCchar alcNoError[] = "No Error";
274 static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
275 static const ALCchar alcErrInvalidContext[] = "Invalid Context";
276 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
277 static const ALCchar alcErrInvalidValue[] = "Invalid Value";
278 static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
279 static const ALCchar alcExtensionList[] =
280 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
281 "ALC_EXT_thread_local_context";
283 static const ALCint alcMajorVersion = 1;
284 static const ALCint alcMinorVersion = 1;
287 static std::recursive_mutex EnumerationLock;
288 static std::mutex ContextSwitchLock;
290 static std::atomic<ALCenum> LastError{ALC_NO_ERROR};
291 static PtrIntMap DeviceIfaceMap;
292 static PtrIntMap ContextIfaceMap;
295 typedef struct EnumeratedList {
296 std::vector<ALCchar> Names;
297 std::vector<ALCint> Indicies;
305 static EnumeratedList DevicesList;
306 static EnumeratedList AllDevicesList;
307 static EnumeratedList CaptureDevicesList;
309 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
311 const ALCchar *name_end = names;
312 if(!name_end) return;
317 TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
319 name_end += strlen(name_end)+1;
321 if(names == name_end)
324 list->Names.reserve(list->Names.size() + (name_end - names) + 1);
325 list->Names.insert(list->Names.cend(), names, name_end);
327 list->Indicies.reserve(list->Indicies.size() + count);
328 list->Indicies.insert(list->Indicies.cend(), count, idx);
331 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
333 const ALCchar *devnames = list->Names.data();
334 const ALCint *index = list->Indicies.data();
336 while(devnames && *devnames)
338 if(strcmp(name, devnames) == 0)
340 devnames += strlen(devnames)+1;
347 static void InitCtxFuncs(DriverIface &iface)
349 ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())};
351 #define LOAD_PROC(x) do { \
352 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
354 ERR("Failed to find entry point for %s in %ls\n", #x, \
355 iface.Name.c_str()); \
357 if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX"))
359 LOAD_PROC(alGenFilters);
360 LOAD_PROC(alDeleteFilters);
361 LOAD_PROC(alIsFilter);
362 LOAD_PROC(alFilterf);
363 LOAD_PROC(alFilterfv);
364 LOAD_PROC(alFilteri);
365 LOAD_PROC(alFilteriv);
366 LOAD_PROC(alGetFilterf);
367 LOAD_PROC(alGetFilterfv);
368 LOAD_PROC(alGetFilteri);
369 LOAD_PROC(alGetFilteriv);
370 LOAD_PROC(alGenEffects);
371 LOAD_PROC(alDeleteEffects);
372 LOAD_PROC(alIsEffect);
373 LOAD_PROC(alEffectf);
374 LOAD_PROC(alEffectfv);
375 LOAD_PROC(alEffecti);
376 LOAD_PROC(alEffectiv);
377 LOAD_PROC(alGetEffectf);
378 LOAD_PROC(alGetEffectfv);
379 LOAD_PROC(alGetEffecti);
380 LOAD_PROC(alGetEffectiv);
381 LOAD_PROC(alGenAuxiliaryEffectSlots);
382 LOAD_PROC(alDeleteAuxiliaryEffectSlots);
383 LOAD_PROC(alIsAuxiliaryEffectSlot);
384 LOAD_PROC(alAuxiliaryEffectSlotf);
385 LOAD_PROC(alAuxiliaryEffectSlotfv);
386 LOAD_PROC(alAuxiliaryEffectSloti);
387 LOAD_PROC(alAuxiliaryEffectSlotiv);
388 LOAD_PROC(alGetAuxiliaryEffectSlotf);
389 LOAD_PROC(alGetAuxiliaryEffectSlotfv);
390 LOAD_PROC(alGetAuxiliaryEffectSloti);
391 LOAD_PROC(alGetAuxiliaryEffectSlotiv);
397 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
399 ALCdevice *device = nullptr;
402 /* Prior to the enumeration extension, apps would hardcode these names as a
403 * quality hint for the wrapper driver. Ignore them since there's no sane
406 if(devicename && (devicename[0] == '\0' ||
407 strcmp(devicename, "DirectSound3D") == 0 ||
408 strcmp(devicename, "DirectSound") == 0 ||
409 strcmp(devicename, "MMSYSTEM") == 0))
410 devicename = nullptr;
414 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
415 if(DevicesList.Names.empty())
416 (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
417 idx = GetDriverIndexForName(&DevicesList, devicename);
420 if(AllDevicesList.Names.empty())
421 (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
422 idx = GetDriverIndexForName(&AllDevicesList, devicename);
428 LastError.store(ALC_INVALID_VALUE);
429 TRACE("Failed to find driver for name \"%s\"\n", devicename);
432 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
433 device = DriverList[idx]->alcOpenDevice(devicename);
437 for(const auto &drv : DriverList)
439 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
440 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
442 TRACE("Using default device from driver %d\n", idx);
443 device = drv->alcOpenDevice(nullptr);
452 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
454 DriverList[idx]->alcCloseDevice(device);
462 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
466 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
468 LastError.store(ALC_INVALID_DEVICE);
471 if(!DriverList[idx]->alcCloseDevice(device))
473 DeviceIfaceMap.removeByKey(device);
478 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
483 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
485 LastError.store(ALC_INVALID_DEVICE);
488 context = DriverList[idx]->alcCreateContext(device, attrlist);
491 if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
493 DriverList[idx]->alcDestroyContext(context);
501 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
505 std::lock_guard<std::mutex> _{ContextSwitchLock};
508 idx = ContextIfaceMap.lookupByKey(context);
511 LastError.store(ALC_INVALID_CONTEXT);
514 if(!DriverList[idx]->alcMakeContextCurrent(context))
517 auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); };
518 std::call_once(DriverList[idx]->InitOnceCtx, do_init);
521 /* Unset the context from the old driver if it's different from the new
526 DriverIface *oldiface = GetThreadDriver();
527 if(oldiface) oldiface->alcSetThreadContext(nullptr);
528 oldiface = CurrentCtxDriver.exchange(nullptr);
529 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
533 DriverIface *oldiface = GetThreadDriver();
534 if(oldiface && oldiface != DriverList[idx].get())
535 oldiface->alcSetThreadContext(nullptr);
536 oldiface = CurrentCtxDriver.exchange(DriverList[idx].get());
537 if(oldiface && oldiface != DriverList[idx].get())
538 oldiface->alcMakeContextCurrent(nullptr);
540 SetThreadDriver(nullptr);
545 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
549 ALint idx = ContextIfaceMap.lookupByKey(context);
551 return DriverList[idx]->alcProcessContext(context);
553 LastError.store(ALC_INVALID_CONTEXT);
556 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
560 ALint idx = ContextIfaceMap.lookupByKey(context);
562 return DriverList[idx]->alcSuspendContext(context);
564 LastError.store(ALC_INVALID_CONTEXT);
567 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
571 if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
573 LastError.store(ALC_INVALID_CONTEXT);
577 DriverList[idx]->alcDestroyContext(context);
578 ContextIfaceMap.removeByKey(context);
581 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
583 DriverIface *iface = GetThreadDriver();
584 if(!iface) iface = CurrentCtxDriver.load();
585 return iface ? iface->alcGetCurrentContext() : nullptr;
588 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
592 ALint idx = ContextIfaceMap.lookupByKey(context);
594 return DriverList[idx]->alcGetContextsDevice(context);
596 LastError.store(ALC_INVALID_CONTEXT);
601 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
605 ALint idx = DeviceIfaceMap.lookupByKey(device);
606 if(idx < 0) return ALC_INVALID_DEVICE;
607 return DriverList[idx]->alcGetError(device);
609 return LastError.exchange(ALC_NO_ERROR);
612 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
619 ALint idx = DeviceIfaceMap.lookupByKey(device);
622 LastError.store(ALC_INVALID_DEVICE);
625 return DriverList[idx]->alcIsExtensionPresent(device, extname);
628 len = strlen(extname);
629 ptr = alcExtensionList;
632 if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
634 if((ptr=strchr(ptr, ' ')) != nullptr)
638 } while(isspace(*ptr));
644 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
648 ALint idx = DeviceIfaceMap.lookupByKey(device);
651 LastError.store(ALC_INVALID_DEVICE);
654 return DriverList[idx]->alcGetProcAddress(device, funcname);
657 auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
658 [funcname](const FuncExportEntry &entry) -> bool
659 { return strcmp(funcname, entry.funcName) == 0; }
661 return (iter != alcFunctions.cend()) ? iter->address : nullptr;
664 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
668 ALint idx = DeviceIfaceMap.lookupByKey(device);
671 LastError.store(ALC_INVALID_DEVICE);
674 return DriverList[idx]->alcGetEnumValue(device, enumname);
677 auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
678 [enumname](const EnumExportEntry &entry) -> bool
679 { return strcmp(enumname, entry.enumName) == 0; }
681 return (iter != alcEnumerations.cend()) ? iter->value : 0;
684 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
688 ALint idx = DeviceIfaceMap.lookupByKey(device);
691 LastError.store(ALC_INVALID_DEVICE);
694 return DriverList[idx]->alcGetString(device, param);
701 case ALC_INVALID_ENUM:
702 return alcErrInvalidEnum;
703 case ALC_INVALID_VALUE:
704 return alcErrInvalidValue;
705 case ALC_INVALID_DEVICE:
706 return alcErrInvalidDevice;
707 case ALC_INVALID_CONTEXT:
708 return alcErrInvalidContext;
709 case ALC_OUT_OF_MEMORY:
710 return alcErrOutOfMemory;
712 return alcExtensionList;
714 case ALC_DEVICE_SPECIFIER:
716 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
719 for(const auto &drv : DriverList)
721 /* Only enumerate names from drivers that support it. */
722 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
723 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
724 AppendDeviceList(&DevicesList,
725 drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
728 /* Ensure the list is double-null termianted. */
729 if(DevicesList.Names.empty())
730 DevicesList.Names.emplace_back('\0');
731 DevicesList.Names.emplace_back('\0');
732 return DevicesList.Names.data();
735 case ALC_ALL_DEVICES_SPECIFIER:
737 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
738 AllDevicesList.clear();
740 for(const auto &drv : DriverList)
742 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
743 * standard enumeration.
745 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
746 AppendDeviceList(&AllDevicesList,
747 drv->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx);
748 else if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
749 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
750 AppendDeviceList(&AllDevicesList,
751 drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
754 /* Ensure the list is double-null termianted. */
755 if(AllDevicesList.Names.empty())
756 AllDevicesList.Names.emplace_back('\0');
757 AllDevicesList.Names.emplace_back('\0');
758 return AllDevicesList.Names.data();
761 case ALC_CAPTURE_DEVICE_SPECIFIER:
763 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
764 CaptureDevicesList.clear();
766 for(const auto &drv : DriverList)
768 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
769 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
770 AppendDeviceList(&CaptureDevicesList,
771 drv->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx);
774 /* Ensure the list is double-null termianted. */
775 if(CaptureDevicesList.Names.empty())
776 CaptureDevicesList.Names.emplace_back('\0');
777 CaptureDevicesList.Names.emplace_back('\0');
778 return CaptureDevicesList.Names.data();
781 case ALC_DEFAULT_DEVICE_SPECIFIER:
783 for(const auto &drv : DriverList)
785 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
786 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
787 return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
792 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
794 for(const auto &drv : DriverList)
796 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE)
797 return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
802 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
804 for(const auto &drv : DriverList)
806 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
807 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
808 return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
814 LastError.store(ALC_INVALID_ENUM);
820 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
824 ALint idx = DeviceIfaceMap.lookupByKey(device);
827 LastError.store(ALC_INVALID_DEVICE);
830 return DriverList[idx]->alcGetIntegerv(device, param, size, values);
833 if(size <= 0 || values == nullptr)
835 LastError.store(ALC_INVALID_VALUE);
841 case ALC_MAJOR_VERSION:
844 values[0] = alcMajorVersion;
848 case ALC_MINOR_VERSION:
851 values[0] = alcMinorVersion;
854 LastError.store(ALC_INVALID_VALUE);
857 case ALC_ATTRIBUTES_SIZE:
858 case ALC_ALL_ATTRIBUTES:
862 case ALC_MONO_SOURCES:
863 case ALC_STEREO_SOURCES:
864 case ALC_CAPTURE_SAMPLES:
865 LastError.store(ALC_INVALID_DEVICE);
869 LastError.store(ALC_INVALID_ENUM);
875 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
877 ALCdevice *device = nullptr;
880 if(devicename && devicename[0] == '\0')
881 devicename = nullptr;
885 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
886 if(CaptureDevicesList.Names.empty())
887 (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
888 idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
893 LastError.store(ALC_INVALID_VALUE);
894 TRACE("Failed to find driver for name \"%s\"\n", devicename);
897 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
898 device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize);
902 for(const auto &drv : DriverList)
904 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
905 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
907 TRACE("Using default capture device from driver %d\n", idx);
908 device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
917 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
919 DriverList[idx]->alcCaptureCloseDevice(device);
927 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
931 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
933 LastError.store(ALC_INVALID_DEVICE);
936 if(!DriverList[idx]->alcCaptureCloseDevice(device))
938 DeviceIfaceMap.removeByKey(device);
942 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
946 ALint idx = DeviceIfaceMap.lookupByKey(device);
948 return DriverList[idx]->alcCaptureStart(device);
950 LastError.store(ALC_INVALID_DEVICE);
953 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
957 ALint idx = DeviceIfaceMap.lookupByKey(device);
959 return DriverList[idx]->alcCaptureStop(device);
961 LastError.store(ALC_INVALID_DEVICE);
964 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
968 ALint idx = DeviceIfaceMap.lookupByKey(device);
970 return DriverList[idx]->alcCaptureSamples(device, buffer, samples);
972 LastError.store(ALC_INVALID_DEVICE);
976 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
978 ALCenum err = ALC_INVALID_CONTEXT;
983 DriverIface *oldiface = GetThreadDriver();
984 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
986 SetThreadDriver(nullptr);
990 idx = ContextIfaceMap.lookupByKey(context);
993 if(DriverList[idx]->alcSetThreadContext(context))
995 auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); };
996 std::call_once(DriverList[idx]->InitOnceCtx, do_init);
998 DriverIface *oldiface = GetThreadDriver();
999 if(oldiface != DriverList[idx].get())
1001 SetThreadDriver(DriverList[idx].get());
1002 if(oldiface) oldiface->alcSetThreadContext(nullptr);
1006 err = DriverList[idx]->alcGetError(nullptr);
1008 LastError.store(err);
1012 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
1014 DriverIface *iface = GetThreadDriver();
1015 if(iface) return iface->alcGetThreadContext();