]> git.tdb.fi Git - ext/openal.git/blob - router/alc.cpp
Import OpenAL Soft 1.23.1 sources
[ext/openal.git] / router / alc.cpp
1
2 #include "config.h"
3
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
8
9 #include <mutex>
10 #include <algorithm>
11 #include <array>
12
13 #include "AL/alc.h"
14 #include "alstring.h"
15 #include "router.h"
16
17
18 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
19 struct FuncExportEntry {
20     const char *funcName;
21     void *address;
22 };
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),
31     DECL(alcOpenDevice),
32     DECL(alcCloseDevice),
33     DECL(alcGetError),
34     DECL(alcIsExtensionPresent),
35     DECL(alcGetProcAddress),
36     DECL(alcGetEnumValue),
37     DECL(alcGetString),
38     DECL(alcGetIntegerv),
39     DECL(alcCaptureOpenDevice),
40     DECL(alcCaptureCloseDevice),
41     DECL(alcCaptureStart),
42     DECL(alcCaptureStop),
43     DECL(alcCaptureSamples),
44
45     DECL(alcSetThreadContext),
46     DECL(alcGetThreadContext),
47
48     DECL(alEnable),
49     DECL(alDisable),
50     DECL(alIsEnabled),
51     DECL(alGetString),
52     DECL(alGetBooleanv),
53     DECL(alGetIntegerv),
54     DECL(alGetFloatv),
55     DECL(alGetDoublev),
56     DECL(alGetBoolean),
57     DECL(alGetInteger),
58     DECL(alGetFloat),
59     DECL(alGetDouble),
60     DECL(alGetError),
61     DECL(alIsExtensionPresent),
62     DECL(alGetProcAddress),
63     DECL(alGetEnumValue),
64     DECL(alListenerf),
65     DECL(alListener3f),
66     DECL(alListenerfv),
67     DECL(alListeneri),
68     DECL(alListener3i),
69     DECL(alListeneriv),
70     DECL(alGetListenerf),
71     DECL(alGetListener3f),
72     DECL(alGetListenerfv),
73     DECL(alGetListeneri),
74     DECL(alGetListener3i),
75     DECL(alGetListeneriv),
76     DECL(alGenSources),
77     DECL(alDeleteSources),
78     DECL(alIsSource),
79     DECL(alSourcef),
80     DECL(alSource3f),
81     DECL(alSourcefv),
82     DECL(alSourcei),
83     DECL(alSource3i),
84     DECL(alSourceiv),
85     DECL(alGetSourcef),
86     DECL(alGetSource3f),
87     DECL(alGetSourcefv),
88     DECL(alGetSourcei),
89     DECL(alGetSource3i),
90     DECL(alGetSourceiv),
91     DECL(alSourcePlayv),
92     DECL(alSourceStopv),
93     DECL(alSourceRewindv),
94     DECL(alSourcePausev),
95     DECL(alSourcePlay),
96     DECL(alSourceStop),
97     DECL(alSourceRewind),
98     DECL(alSourcePause),
99     DECL(alSourceQueueBuffers),
100     DECL(alSourceUnqueueBuffers),
101     DECL(alGenBuffers),
102     DECL(alDeleteBuffers),
103     DECL(alIsBuffer),
104     DECL(alBufferData),
105     DECL(alBufferf),
106     DECL(alBuffer3f),
107     DECL(alBufferfv),
108     DECL(alBufferi),
109     DECL(alBuffer3i),
110     DECL(alBufferiv),
111     DECL(alGetBufferf),
112     DECL(alGetBuffer3f),
113     DECL(alGetBufferfv),
114     DECL(alGetBufferi),
115     DECL(alGetBuffer3i),
116     DECL(alGetBufferiv),
117     DECL(alDopplerFactor),
118     DECL(alDopplerVelocity),
119     DECL(alSpeedOfSound),
120     DECL(alDistanceModel),
121
122     /* EFX 1.0 */
123     DECL(alGenFilters),
124     DECL(alDeleteFilters),
125     DECL(alIsFilter),
126     DECL(alFilterf),
127     DECL(alFilterfv),
128     DECL(alFilteri),
129     DECL(alFilteriv),
130     DECL(alGetFilterf),
131     DECL(alGetFilterfv),
132     DECL(alGetFilteri),
133     DECL(alGetFilteriv),
134     DECL(alGenEffects),
135     DECL(alDeleteEffects),
136     DECL(alIsEffect),
137     DECL(alEffectf),
138     DECL(alEffectfv),
139     DECL(alEffecti),
140     DECL(alEffectiv),
141     DECL(alGetEffectf),
142     DECL(alGetEffectfv),
143     DECL(alGetEffecti),
144     DECL(alGetEffectiv),
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),
156 }};
157 #undef DECL
158
159 #define DECL(x) { #x, (x) }
160 struct EnumExportEntry {
161     const ALCchar *enumName;
162     ALCenum value;
163 };
164 static const std::array<EnumExportEntry,92> alcEnumerations{{
165     DECL(ALC_INVALID),
166     DECL(ALC_FALSE),
167     DECL(ALC_TRUE),
168
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),
178     DECL(ALC_FREQUENCY),
179     DECL(ALC_REFRESH),
180     DECL(ALC_SYNC),
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),
186
187     DECL(ALC_NO_ERROR),
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),
193
194     DECL(AL_INVALID),
195     DECL(AL_NONE),
196     DECL(AL_FALSE),
197     DECL(AL_TRUE),
198
199     DECL(AL_SOURCE_RELATIVE),
200     DECL(AL_CONE_INNER_ANGLE),
201     DECL(AL_CONE_OUTER_ANGLE),
202     DECL(AL_PITCH),
203     DECL(AL_POSITION),
204     DECL(AL_DIRECTION),
205     DECL(AL_VELOCITY),
206     DECL(AL_LOOPING),
207     DECL(AL_BUFFER),
208     DECL(AL_GAIN),
209     DECL(AL_MIN_GAIN),
210     DECL(AL_MAX_GAIN),
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),
216     DECL(AL_SEC_OFFSET),
217     DECL(AL_SAMPLE_OFFSET),
218     DECL(AL_BYTE_OFFSET),
219     DECL(AL_SOURCE_TYPE),
220     DECL(AL_STATIC),
221     DECL(AL_STREAMING),
222     DECL(AL_UNDETERMINED),
223
224     DECL(AL_SOURCE_STATE),
225     DECL(AL_INITIAL),
226     DECL(AL_PLAYING),
227     DECL(AL_PAUSED),
228     DECL(AL_STOPPED),
229
230     DECL(AL_BUFFERS_QUEUED),
231     DECL(AL_BUFFERS_PROCESSED),
232
233     DECL(AL_FORMAT_MONO8),
234     DECL(AL_FORMAT_MONO16),
235     DECL(AL_FORMAT_STEREO8),
236     DECL(AL_FORMAT_STEREO16),
237
238     DECL(AL_FREQUENCY),
239     DECL(AL_BITS),
240     DECL(AL_CHANNELS),
241     DECL(AL_SIZE),
242
243     DECL(AL_UNUSED),
244     DECL(AL_PENDING),
245     DECL(AL_PROCESSED),
246
247     DECL(AL_NO_ERROR),
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),
253
254     DECL(AL_VENDOR),
255     DECL(AL_VERSION),
256     DECL(AL_RENDERER),
257     DECL(AL_EXTENSIONS),
258
259     DECL(AL_DOPPLER_FACTOR),
260     DECL(AL_DOPPLER_VELOCITY),
261     DECL(AL_DISTANCE_MODEL),
262     DECL(AL_SPEED_OF_SOUND),
263
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),
270 }};
271 #undef DECL
272
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";
282
283 static const ALCint alcMajorVersion = 1;
284 static const ALCint alcMinorVersion = 1;
285
286
287 static std::recursive_mutex EnumerationLock;
288 static std::mutex ContextSwitchLock;
289
290 static std::atomic<ALCenum> LastError{ALC_NO_ERROR};
291 static PtrIntMap DeviceIfaceMap;
292 static PtrIntMap ContextIfaceMap;
293
294
295 typedef struct EnumeratedList {
296     std::vector<ALCchar> Names;
297     std::vector<ALCint> Indicies;
298
299     void clear()
300     {
301         Names.clear();
302         Indicies.clear();
303     }
304 } EnumeratedList;
305 static EnumeratedList DevicesList;
306 static EnumeratedList AllDevicesList;
307 static EnumeratedList CaptureDevicesList;
308
309 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
310 {
311     const ALCchar *name_end = names;
312     if(!name_end) return;
313
314     ALCsizei count = 0;
315     while(*name_end)
316     {
317         TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
318         ++count;
319         name_end += strlen(name_end)+1;
320     }
321     if(names == name_end)
322         return;
323
324     list->Names.reserve(list->Names.size() + (name_end - names) + 1);
325     list->Names.insert(list->Names.cend(), names, name_end);
326
327     list->Indicies.reserve(list->Indicies.size() + count);
328     list->Indicies.insert(list->Indicies.cend(), count, idx);
329 }
330
331 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
332 {
333     const ALCchar *devnames = list->Names.data();
334     const ALCint *index = list->Indicies.data();
335
336     while(devnames && *devnames)
337     {
338         if(strcmp(name, devnames) == 0)
339             return *index;
340         devnames += strlen(devnames)+1;
341         index++;
342     }
343     return -1;
344 }
345
346
347 static void InitCtxFuncs(DriverIface &iface)
348 {
349     ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())};
350
351 #define LOAD_PROC(x) do {                                                     \
352     iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
353     if(!iface.x)                                                              \
354         ERR("Failed to find entry point for %s in %ls\n", #x,                 \
355             iface.Name.c_str());                                              \
356 } while(0)
357     if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX"))
358     {
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);
392     }
393 #undef LOAD_PROC
394 }
395
396
397 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
398 {
399     ALCdevice *device = nullptr;
400     ALint idx = 0;
401
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
404      * way to map them.
405      */
406     if(devicename && (devicename[0] == '\0' ||
407                       strcmp(devicename, "DirectSound3D") == 0 ||
408                       strcmp(devicename, "DirectSound") == 0 ||
409                       strcmp(devicename, "MMSYSTEM") == 0))
410         devicename = nullptr;
411     if(devicename)
412     {
413         {
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);
418             if(idx < 0)
419             {
420                 if(AllDevicesList.Names.empty())
421                     (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
422                 idx = GetDriverIndexForName(&AllDevicesList, devicename);
423             }
424         }
425
426         if(idx < 0)
427         {
428             LastError.store(ALC_INVALID_VALUE);
429             TRACE("Failed to find driver for name \"%s\"\n", devicename);
430             return nullptr;
431         }
432         TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
433         device = DriverList[idx]->alcOpenDevice(devicename);
434     }
435     else
436     {
437         for(const auto &drv : DriverList)
438         {
439             if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
440                 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
441             {
442                 TRACE("Using default device from driver %d\n", idx);
443                 device = drv->alcOpenDevice(nullptr);
444                 break;
445             }
446             ++idx;
447         }
448     }
449
450     if(device)
451     {
452         if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
453         {
454             DriverList[idx]->alcCloseDevice(device);
455             device = nullptr;
456         }
457     }
458
459     return device;
460 }
461
462 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
463 {
464     ALint idx;
465
466     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
467     {
468         LastError.store(ALC_INVALID_DEVICE);
469         return ALC_FALSE;
470     }
471     if(!DriverList[idx]->alcCloseDevice(device))
472         return ALC_FALSE;
473     DeviceIfaceMap.removeByKey(device);
474     return ALC_TRUE;
475 }
476
477
478 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
479 {
480     ALCcontext *context;
481     ALint idx;
482
483     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
484     {
485         LastError.store(ALC_INVALID_DEVICE);
486         return nullptr;
487     }
488     context = DriverList[idx]->alcCreateContext(device, attrlist);
489     if(context)
490     {
491         if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
492         {
493             DriverList[idx]->alcDestroyContext(context);
494             context = nullptr;
495         }
496     }
497
498     return context;
499 }
500
501 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
502 {
503     ALint idx = -1;
504
505     std::lock_guard<std::mutex> _{ContextSwitchLock};
506     if(context)
507     {
508         idx = ContextIfaceMap.lookupByKey(context);
509         if(idx < 0)
510         {
511             LastError.store(ALC_INVALID_CONTEXT);
512             return ALC_FALSE;
513         }
514         if(!DriverList[idx]->alcMakeContextCurrent(context))
515             return ALC_FALSE;
516
517         auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); };
518         std::call_once(DriverList[idx]->InitOnceCtx, do_init);
519     }
520
521     /* Unset the context from the old driver if it's different from the new
522      * current one.
523      */
524     if(idx < 0)
525     {
526         DriverIface *oldiface = GetThreadDriver();
527         if(oldiface) oldiface->alcSetThreadContext(nullptr);
528         oldiface = CurrentCtxDriver.exchange(nullptr);
529         if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
530     }
531     else
532     {
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);
539     }
540     SetThreadDriver(nullptr);
541
542     return ALC_TRUE;
543 }
544
545 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
546 {
547     if(context)
548     {
549         ALint idx = ContextIfaceMap.lookupByKey(context);
550         if(idx >= 0)
551             return DriverList[idx]->alcProcessContext(context);
552     }
553     LastError.store(ALC_INVALID_CONTEXT);
554 }
555
556 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
557 {
558     if(context)
559     {
560         ALint idx = ContextIfaceMap.lookupByKey(context);
561         if(idx >= 0)
562             return DriverList[idx]->alcSuspendContext(context);
563     }
564     LastError.store(ALC_INVALID_CONTEXT);
565 }
566
567 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
568 {
569     ALint idx;
570
571     if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
572     {
573         LastError.store(ALC_INVALID_CONTEXT);
574         return;
575     }
576
577     DriverList[idx]->alcDestroyContext(context);
578     ContextIfaceMap.removeByKey(context);
579 }
580
581 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
582 {
583     DriverIface *iface = GetThreadDriver();
584     if(!iface) iface = CurrentCtxDriver.load();
585     return iface ? iface->alcGetCurrentContext() : nullptr;
586 }
587
588 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
589 {
590     if(context)
591     {
592         ALint idx = ContextIfaceMap.lookupByKey(context);
593         if(idx >= 0)
594             return DriverList[idx]->alcGetContextsDevice(context);
595     }
596     LastError.store(ALC_INVALID_CONTEXT);
597     return nullptr;
598 }
599
600
601 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
602 {
603     if(device)
604     {
605         ALint idx = DeviceIfaceMap.lookupByKey(device);
606         if(idx < 0) return ALC_INVALID_DEVICE;
607         return DriverList[idx]->alcGetError(device);
608     }
609     return LastError.exchange(ALC_NO_ERROR);
610 }
611
612 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
613 {
614     const char *ptr;
615     size_t len;
616
617     if(device)
618     {
619         ALint idx = DeviceIfaceMap.lookupByKey(device);
620         if(idx < 0)
621         {
622             LastError.store(ALC_INVALID_DEVICE);
623             return ALC_FALSE;
624         }
625         return DriverList[idx]->alcIsExtensionPresent(device, extname);
626     }
627
628     len = strlen(extname);
629     ptr = alcExtensionList;
630     while(ptr && *ptr)
631     {
632         if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
633             return ALC_TRUE;
634         if((ptr=strchr(ptr, ' ')) != nullptr)
635         {
636             do {
637                 ++ptr;
638             } while(isspace(*ptr));
639         }
640     }
641     return ALC_FALSE;
642 }
643
644 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
645 {
646     if(device)
647     {
648         ALint idx = DeviceIfaceMap.lookupByKey(device);
649         if(idx < 0)
650         {
651             LastError.store(ALC_INVALID_DEVICE);
652             return nullptr;
653         }
654         return DriverList[idx]->alcGetProcAddress(device, funcname);
655     }
656
657     auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
658         [funcname](const FuncExportEntry &entry) -> bool
659         { return strcmp(funcname, entry.funcName) == 0; }
660     );
661     return (iter != alcFunctions.cend()) ? iter->address : nullptr;
662 }
663
664 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
665 {
666     if(device)
667     {
668         ALint idx = DeviceIfaceMap.lookupByKey(device);
669         if(idx < 0)
670         {
671             LastError.store(ALC_INVALID_DEVICE);
672             return 0;
673         }
674         return DriverList[idx]->alcGetEnumValue(device, enumname);
675     }
676
677     auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
678         [enumname](const EnumExportEntry &entry) -> bool
679         { return strcmp(enumname, entry.enumName) == 0; }
680     );
681     return (iter != alcEnumerations.cend()) ? iter->value : 0;
682 }
683
684 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
685 {
686     if(device)
687     {
688         ALint idx = DeviceIfaceMap.lookupByKey(device);
689         if(idx < 0)
690         {
691             LastError.store(ALC_INVALID_DEVICE);
692             return nullptr;
693         }
694         return DriverList[idx]->alcGetString(device, param);
695     }
696
697     switch(param)
698     {
699     case ALC_NO_ERROR:
700         return alcNoError;
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;
711     case ALC_EXTENSIONS:
712         return alcExtensionList;
713
714     case ALC_DEVICE_SPECIFIER:
715     {
716         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
717         DevicesList.clear();
718         ALint idx{0};
719         for(const auto &drv : DriverList)
720         {
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);
726             ++idx;
727         }
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();
733     }
734
735     case ALC_ALL_DEVICES_SPECIFIER:
736     {
737         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
738         AllDevicesList.clear();
739         ALint idx{0};
740         for(const auto &drv : DriverList)
741         {
742             /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
743              * standard enumeration.
744              */
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);
752             ++idx;
753         }
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();
759     }
760
761     case ALC_CAPTURE_DEVICE_SPECIFIER:
762     {
763         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
764         CaptureDevicesList.clear();
765         ALint idx{0};
766         for(const auto &drv : DriverList)
767         {
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);
772             ++idx;
773         }
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();
779     }
780
781     case ALC_DEFAULT_DEVICE_SPECIFIER:
782     {
783         for(const auto &drv : DriverList)
784         {
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);
788         }
789         return "";
790     }
791
792     case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
793     {
794         for(const auto &drv : DriverList)
795         {
796             if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE)
797                 return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
798         }
799         return "";
800     }
801
802     case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
803     {
804         for(const auto &drv : DriverList)
805         {
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);
809         }
810         return "";
811     }
812
813     default:
814         LastError.store(ALC_INVALID_ENUM);
815         break;
816     }
817     return nullptr;
818 }
819
820 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
821 {
822     if(device)
823     {
824         ALint idx = DeviceIfaceMap.lookupByKey(device);
825         if(idx < 0)
826         {
827             LastError.store(ALC_INVALID_DEVICE);
828             return;
829         }
830         return DriverList[idx]->alcGetIntegerv(device, param, size, values);
831     }
832
833     if(size <= 0 || values == nullptr)
834     {
835         LastError.store(ALC_INVALID_VALUE);
836         return;
837     }
838
839     switch(param)
840     {
841         case ALC_MAJOR_VERSION:
842             if(size >= 1)
843             {
844                 values[0] = alcMajorVersion;
845                 return;
846             }
847             /*fall-through*/
848         case ALC_MINOR_VERSION:
849             if(size >= 1)
850             {
851                 values[0] = alcMinorVersion;
852                 return;
853             }
854             LastError.store(ALC_INVALID_VALUE);
855             return;
856
857         case ALC_ATTRIBUTES_SIZE:
858         case ALC_ALL_ATTRIBUTES:
859         case ALC_FREQUENCY:
860         case ALC_REFRESH:
861         case ALC_SYNC:
862         case ALC_MONO_SOURCES:
863         case ALC_STEREO_SOURCES:
864         case ALC_CAPTURE_SAMPLES:
865             LastError.store(ALC_INVALID_DEVICE);
866             return;
867
868         default:
869             LastError.store(ALC_INVALID_ENUM);
870             return;
871     }
872 }
873
874
875 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
876 {
877     ALCdevice *device = nullptr;
878     ALint idx = 0;
879
880     if(devicename && devicename[0] == '\0')
881         devicename = nullptr;
882     if(devicename)
883     {
884         {
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);
889         }
890
891         if(idx < 0)
892         {
893             LastError.store(ALC_INVALID_VALUE);
894             TRACE("Failed to find driver for name \"%s\"\n", devicename);
895             return nullptr;
896         }
897         TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
898         device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize);
899     }
900     else
901     {
902         for(const auto &drv : DriverList)
903         {
904             if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
905                 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
906             {
907                 TRACE("Using default capture device from driver %d\n", idx);
908                 device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
909                 break;
910             }
911             ++idx;
912         }
913     }
914
915     if(device)
916     {
917         if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
918         {
919             DriverList[idx]->alcCaptureCloseDevice(device);
920             device = nullptr;
921         }
922     }
923
924     return device;
925 }
926
927 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
928 {
929     ALint idx;
930
931     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
932     {
933         LastError.store(ALC_INVALID_DEVICE);
934         return ALC_FALSE;
935     }
936     if(!DriverList[idx]->alcCaptureCloseDevice(device))
937         return ALC_FALSE;
938     DeviceIfaceMap.removeByKey(device);
939     return ALC_TRUE;
940 }
941
942 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
943 {
944     if(device)
945     {
946         ALint idx = DeviceIfaceMap.lookupByKey(device);
947         if(idx >= 0)
948             return DriverList[idx]->alcCaptureStart(device);
949     }
950     LastError.store(ALC_INVALID_DEVICE);
951 }
952
953 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
954 {
955     if(device)
956     {
957         ALint idx = DeviceIfaceMap.lookupByKey(device);
958         if(idx >= 0)
959             return DriverList[idx]->alcCaptureStop(device);
960     }
961     LastError.store(ALC_INVALID_DEVICE);
962 }
963
964 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
965 {
966     if(device)
967     {
968         ALint idx = DeviceIfaceMap.lookupByKey(device);
969         if(idx >= 0)
970             return DriverList[idx]->alcCaptureSamples(device, buffer, samples);
971     }
972     LastError.store(ALC_INVALID_DEVICE);
973 }
974
975
976 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
977 {
978     ALCenum err = ALC_INVALID_CONTEXT;
979     ALint idx;
980
981     if(!context)
982     {
983         DriverIface *oldiface = GetThreadDriver();
984         if(oldiface && !oldiface->alcSetThreadContext(nullptr))
985             return ALC_FALSE;
986         SetThreadDriver(nullptr);
987         return ALC_TRUE;
988     }
989
990     idx = ContextIfaceMap.lookupByKey(context);
991     if(idx >= 0)
992     {
993         if(DriverList[idx]->alcSetThreadContext(context))
994         {
995             auto do_init = [idx]() { InitCtxFuncs(*DriverList[idx]); };
996             std::call_once(DriverList[idx]->InitOnceCtx, do_init);
997
998             DriverIface *oldiface = GetThreadDriver();
999             if(oldiface != DriverList[idx].get())
1000             {
1001                 SetThreadDriver(DriverList[idx].get());
1002                 if(oldiface) oldiface->alcSetThreadContext(nullptr);
1003             }
1004             return ALC_TRUE;
1005         }
1006         err = DriverList[idx]->alcGetError(nullptr);
1007     }
1008     LastError.store(err);
1009     return ALC_FALSE;
1010 }
1011
1012 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
1013 {
1014     DriverIface *iface = GetThreadDriver();
1015     if(iface) return iface->alcGetThreadContext();
1016     return nullptr;
1017 }