Mark some conditionally-used parameters as maybe_unused
[openal-soft.git] / router / alc.cpp
blob58ba446412b8f100146651e0cb651c5201d22686
2 #include "config.h"
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
9 #include <algorithm>
10 #include <array>
11 #include <mutex>
12 #include <tuple>
14 #include "AL/alc.h"
15 #include "alstring.h"
16 #include "router.h"
19 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
20 struct FuncExportEntry {
21 const char *funcName;
22 void *address;
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),
32 DECL(alcOpenDevice),
33 DECL(alcCloseDevice),
34 DECL(alcGetError),
35 DECL(alcIsExtensionPresent),
36 DECL(alcGetProcAddress),
37 DECL(alcGetEnumValue),
38 DECL(alcGetString),
39 DECL(alcGetIntegerv),
40 DECL(alcCaptureOpenDevice),
41 DECL(alcCaptureCloseDevice),
42 DECL(alcCaptureStart),
43 DECL(alcCaptureStop),
44 DECL(alcCaptureSamples),
46 DECL(alcSetThreadContext),
47 DECL(alcGetThreadContext),
49 DECL(alEnable),
50 DECL(alDisable),
51 DECL(alIsEnabled),
52 DECL(alGetString),
53 DECL(alGetBooleanv),
54 DECL(alGetIntegerv),
55 DECL(alGetFloatv),
56 DECL(alGetDoublev),
57 DECL(alGetBoolean),
58 DECL(alGetInteger),
59 DECL(alGetFloat),
60 DECL(alGetDouble),
61 DECL(alGetError),
62 DECL(alIsExtensionPresent),
63 DECL(alGetProcAddress),
64 DECL(alGetEnumValue),
65 DECL(alListenerf),
66 DECL(alListener3f),
67 DECL(alListenerfv),
68 DECL(alListeneri),
69 DECL(alListener3i),
70 DECL(alListeneriv),
71 DECL(alGetListenerf),
72 DECL(alGetListener3f),
73 DECL(alGetListenerfv),
74 DECL(alGetListeneri),
75 DECL(alGetListener3i),
76 DECL(alGetListeneriv),
77 DECL(alGenSources),
78 DECL(alDeleteSources),
79 DECL(alIsSource),
80 DECL(alSourcef),
81 DECL(alSource3f),
82 DECL(alSourcefv),
83 DECL(alSourcei),
84 DECL(alSource3i),
85 DECL(alSourceiv),
86 DECL(alGetSourcef),
87 DECL(alGetSource3f),
88 DECL(alGetSourcefv),
89 DECL(alGetSourcei),
90 DECL(alGetSource3i),
91 DECL(alGetSourceiv),
92 DECL(alSourcePlayv),
93 DECL(alSourceStopv),
94 DECL(alSourceRewindv),
95 DECL(alSourcePausev),
96 DECL(alSourcePlay),
97 DECL(alSourceStop),
98 DECL(alSourceRewind),
99 DECL(alSourcePause),
100 DECL(alSourceQueueBuffers),
101 DECL(alSourceUnqueueBuffers),
102 DECL(alGenBuffers),
103 DECL(alDeleteBuffers),
104 DECL(alIsBuffer),
105 DECL(alBufferData),
106 DECL(alBufferf),
107 DECL(alBuffer3f),
108 DECL(alBufferfv),
109 DECL(alBufferi),
110 DECL(alBuffer3i),
111 DECL(alBufferiv),
112 DECL(alGetBufferf),
113 DECL(alGetBuffer3f),
114 DECL(alGetBufferfv),
115 DECL(alGetBufferi),
116 DECL(alGetBuffer3i),
117 DECL(alGetBufferiv),
118 DECL(alDopplerFactor),
119 DECL(alDopplerVelocity),
120 DECL(alSpeedOfSound),
121 DECL(alDistanceModel),
123 /* EFX 1.0 */
124 DECL(alGenFilters),
125 DECL(alDeleteFilters),
126 DECL(alIsFilter),
127 DECL(alFilterf),
128 DECL(alFilterfv),
129 DECL(alFilteri),
130 DECL(alFilteriv),
131 DECL(alGetFilterf),
132 DECL(alGetFilterfv),
133 DECL(alGetFilteri),
134 DECL(alGetFilteriv),
135 DECL(alGenEffects),
136 DECL(alDeleteEffects),
137 DECL(alIsEffect),
138 DECL(alEffectf),
139 DECL(alEffectfv),
140 DECL(alEffecti),
141 DECL(alEffectiv),
142 DECL(alGetEffectf),
143 DECL(alGetEffectfv),
144 DECL(alGetEffecti),
145 DECL(alGetEffectiv),
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),
158 #undef DECL
160 #define DECL(x) { #x, (x) }
161 struct EnumExportEntry {
162 const ALCchar *enumName;
163 ALCenum value;
165 static const std::array<EnumExportEntry,92> alcEnumerations{{
166 DECL(ALC_INVALID),
167 DECL(ALC_FALSE),
168 DECL(ALC_TRUE),
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),
179 DECL(ALC_FREQUENCY),
180 DECL(ALC_REFRESH),
181 DECL(ALC_SYNC),
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),
188 DECL(ALC_NO_ERROR),
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),
195 DECL(AL_INVALID),
196 DECL(AL_NONE),
197 DECL(AL_FALSE),
198 DECL(AL_TRUE),
200 DECL(AL_SOURCE_RELATIVE),
201 DECL(AL_CONE_INNER_ANGLE),
202 DECL(AL_CONE_OUTER_ANGLE),
203 DECL(AL_PITCH),
204 DECL(AL_POSITION),
205 DECL(AL_DIRECTION),
206 DECL(AL_VELOCITY),
207 DECL(AL_LOOPING),
208 DECL(AL_BUFFER),
209 DECL(AL_GAIN),
210 DECL(AL_MIN_GAIN),
211 DECL(AL_MAX_GAIN),
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),
217 DECL(AL_SEC_OFFSET),
218 DECL(AL_SAMPLE_OFFSET),
219 DECL(AL_BYTE_OFFSET),
220 DECL(AL_SOURCE_TYPE),
221 DECL(AL_STATIC),
222 DECL(AL_STREAMING),
223 DECL(AL_UNDETERMINED),
225 DECL(AL_SOURCE_STATE),
226 DECL(AL_INITIAL),
227 DECL(AL_PLAYING),
228 DECL(AL_PAUSED),
229 DECL(AL_STOPPED),
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),
239 DECL(AL_FREQUENCY),
240 DECL(AL_BITS),
241 DECL(AL_CHANNELS),
242 DECL(AL_SIZE),
244 DECL(AL_UNUSED),
245 DECL(AL_PENDING),
246 DECL(AL_PROCESSED),
248 DECL(AL_NO_ERROR),
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),
255 DECL(AL_VENDOR),
256 DECL(AL_VERSION),
257 DECL(AL_RENDERER),
258 DECL(AL_EXTENSIONS),
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),
272 #undef DECL
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;
300 void clear()
302 Names.clear();
303 Indicies.clear();
305 } EnumeratedList;
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;
315 ALCsizei count = 0;
316 while(*name_end)
318 TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
319 ++count;
320 name_end += strlen(name_end)+1;
322 if(names == name_end)
323 return;
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)
340 return *index;
341 devnames += strlen(devnames)+1;
342 index++;
344 return -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));\
354 if(!iface.x) \
355 ERR("Failed to find entry point for %s in %ls\n", #x, \
356 iface.Name.c_str()); \
357 } while(0)
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);
394 #undef LOAD_PROC
398 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) noexcept
400 ALCdevice *device = nullptr;
401 ALint idx = 0;
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
405 * way to map them.
407 if(devicename && (devicename[0] == '\0' ||
408 strcmp(devicename, "DirectSound3D") == 0 ||
409 strcmp(devicename, "DirectSound") == 0 ||
410 strcmp(devicename, "MMSYSTEM") == 0))
411 devicename = nullptr;
412 if(devicename)
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);
419 if(idx < 0)
421 if(AllDevicesList.Names.empty())
422 std::ignore = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
423 idx = GetDriverIndexForName(&AllDevicesList, devicename);
427 if(idx < 0)
429 LastError.store(ALC_INVALID_VALUE);
430 TRACE("Failed to find driver for name \"%s\"\n", devicename);
431 return nullptr;
433 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
434 device = DriverList[idx]->alcOpenDevice(devicename);
436 else
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);
445 break;
447 ++idx;
451 if(device)
453 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
455 DriverList[idx]->alcCloseDevice(device);
456 device = nullptr;
460 return device;
463 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept
465 ALint idx;
467 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
469 LastError.store(ALC_INVALID_DEVICE);
470 return ALC_FALSE;
472 if(!DriverList[idx]->alcCloseDevice(device))
473 return ALC_FALSE;
474 DeviceIfaceMap.removeByKey(device);
475 return ALC_TRUE;
479 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) noexcept
481 ALCcontext *context;
482 ALint idx;
484 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
486 LastError.store(ALC_INVALID_DEVICE);
487 return nullptr;
489 context = DriverList[idx]->alcCreateContext(device, attrlist);
490 if(context)
492 if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
494 DriverList[idx]->alcDestroyContext(context);
495 context = nullptr;
499 return context;
502 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexcept
504 ALint idx = -1;
506 std::lock_guard<std::mutex> ctxlock{ContextSwitchLock};
507 if(context)
509 idx = ContextIfaceMap.lookupByKey(context);
510 if(idx < 0)
512 LastError.store(ALC_INVALID_CONTEXT);
513 return ALC_FALSE;
515 if(!DriverList[idx]->alcMakeContextCurrent(context))
516 return ALC_FALSE;
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
523 * current one.
525 if(idx < 0)
527 DriverIface *oldiface = GetThreadDriver();
528 if(oldiface) oldiface->alcSetThreadContext(nullptr);
529 oldiface = CurrentCtxDriver.exchange(nullptr);
530 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
532 else
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);
543 return ALC_TRUE;
546 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) noexcept
548 if(context)
550 ALint idx = ContextIfaceMap.lookupByKey(context);
551 if(idx >= 0)
552 return DriverList[idx]->alcProcessContext(context);
554 LastError.store(ALC_INVALID_CONTEXT);
557 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) noexcept
559 if(context)
561 ALint idx = ContextIfaceMap.lookupByKey(context);
562 if(idx >= 0)
563 return DriverList[idx]->alcSuspendContext(context);
565 LastError.store(ALC_INVALID_CONTEXT);
568 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept
570 ALint idx;
572 if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
574 LastError.store(ALC_INVALID_CONTEXT);
575 return;
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
591 if(context)
593 ALint idx = ContextIfaceMap.lookupByKey(context);
594 if(idx >= 0)
595 return DriverList[idx]->alcGetContextsDevice(context);
597 LastError.store(ALC_INVALID_CONTEXT);
598 return nullptr;
602 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) noexcept
604 if(device)
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
615 const char *ptr;
616 size_t len;
618 if(device)
620 ALint idx = DeviceIfaceMap.lookupByKey(device);
621 if(idx < 0)
623 LastError.store(ALC_INVALID_DEVICE);
624 return ALC_FALSE;
626 return DriverList[idx]->alcIsExtensionPresent(device, extname);
629 len = strlen(extname);
630 ptr = alcExtensionList;
631 while(ptr && *ptr)
633 if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
634 return ALC_TRUE;
635 if((ptr=strchr(ptr, ' ')) != nullptr)
637 do {
638 ++ptr;
639 } while(isspace(*ptr));
642 return ALC_FALSE;
645 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) noexcept
647 if(device)
649 ALint idx = DeviceIfaceMap.lookupByKey(device);
650 if(idx < 0)
652 LastError.store(ALC_INVALID_DEVICE);
653 return nullptr;
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
667 if(device)
669 ALint idx = DeviceIfaceMap.lookupByKey(device);
670 if(idx < 0)
672 LastError.store(ALC_INVALID_DEVICE);
673 return 0;
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
687 if(device)
689 ALint idx = DeviceIfaceMap.lookupByKey(device);
690 if(idx < 0)
692 LastError.store(ALC_INVALID_DEVICE);
693 return nullptr;
695 return DriverList[idx]->alcGetString(device, param);
698 switch(param)
700 case ALC_NO_ERROR:
701 return alcNoError;
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;
712 case ALC_EXTENSIONS:
713 return alcExtensionList;
715 case ALC_DEVICE_SPECIFIER:
717 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
718 DevicesList.clear();
719 ALint idx{0};
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);
727 ++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();
740 ALint idx{0};
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);
753 ++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();
766 ALint idx{0};
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);
773 ++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);
790 return "";
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);
800 return "";
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);
811 return "";
814 default:
815 LastError.store(ALC_INVALID_ENUM);
816 break;
818 return nullptr;
821 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) noexcept
823 if(device)
825 ALint idx = DeviceIfaceMap.lookupByKey(device);
826 if(idx < 0)
828 LastError.store(ALC_INVALID_DEVICE);
829 return;
831 return DriverList[idx]->alcGetIntegerv(device, param, size, values);
834 if(size <= 0 || values == nullptr)
836 LastError.store(ALC_INVALID_VALUE);
837 return;
840 switch(param)
842 case ALC_MAJOR_VERSION:
843 if(size >= 1)
845 values[0] = alcMajorVersion;
846 return;
848 /*fall-through*/
849 case ALC_MINOR_VERSION:
850 if(size >= 1)
852 values[0] = alcMinorVersion;
853 return;
855 LastError.store(ALC_INVALID_VALUE);
856 return;
858 case ALC_ATTRIBUTES_SIZE:
859 case ALC_ALL_ATTRIBUTES:
860 case ALC_FREQUENCY:
861 case ALC_REFRESH:
862 case ALC_SYNC:
863 case ALC_MONO_SOURCES:
864 case ALC_STEREO_SOURCES:
865 case ALC_CAPTURE_SAMPLES:
866 LastError.store(ALC_INVALID_DEVICE);
867 return;
869 default:
870 LastError.store(ALC_INVALID_ENUM);
871 return;
876 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) noexcept
878 ALCdevice *device = nullptr;
879 ALint idx = 0;
881 if(devicename && devicename[0] == '\0')
882 devicename = nullptr;
883 if(devicename)
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);
892 if(idx < 0)
894 LastError.store(ALC_INVALID_VALUE);
895 TRACE("Failed to find driver for name \"%s\"\n", devicename);
896 return nullptr;
898 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
899 device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize);
901 else
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);
910 break;
912 ++idx;
916 if(device)
918 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
920 DriverList[idx]->alcCaptureCloseDevice(device);
921 device = nullptr;
925 return device;
928 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) noexcept
930 ALint idx;
932 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
934 LastError.store(ALC_INVALID_DEVICE);
935 return ALC_FALSE;
937 if(!DriverList[idx]->alcCaptureCloseDevice(device))
938 return ALC_FALSE;
939 DeviceIfaceMap.removeByKey(device);
940 return ALC_TRUE;
943 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) noexcept
945 if(device)
947 ALint idx = DeviceIfaceMap.lookupByKey(device);
948 if(idx >= 0)
949 return DriverList[idx]->alcCaptureStart(device);
951 LastError.store(ALC_INVALID_DEVICE);
954 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) noexcept
956 if(device)
958 ALint idx = DeviceIfaceMap.lookupByKey(device);
959 if(idx >= 0)
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
967 if(device)
969 ALint idx = DeviceIfaceMap.lookupByKey(device);
970 if(idx >= 0)
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;
980 ALint idx;
982 if(!context)
984 DriverIface *oldiface = GetThreadDriver();
985 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
986 return ALC_FALSE;
987 SetThreadDriver(nullptr);
988 return ALC_TRUE;
991 idx = ContextIfaceMap.lookupByKey(context);
992 if(idx >= 0)
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);
1005 return ALC_TRUE;
1007 err = DriverList[idx]->alcGetError(nullptr);
1009 LastError.store(err);
1010 return ALC_FALSE;
1013 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext() noexcept
1015 DriverIface *iface = GetThreadDriver();
1016 if(iface) return iface->alcGetThreadContext();
1017 return nullptr;