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     DECL(alGenFilters),
123     DECL(alDeleteFilters),
124     DECL(alIsFilter),
125     DECL(alFilterf),
126     DECL(alFilterfv),
127     DECL(alFilteri),
128     DECL(alFilteriv),
129     DECL(alGetFilterf),
130     DECL(alGetFilterfv),
131     DECL(alGetFilteri),
132     DECL(alGetFilteriv),
133     DECL(alGenEffects),
134     DECL(alDeleteEffects),
135     DECL(alIsEffect),
136     DECL(alEffectf),
137     DECL(alEffectfv),
138     DECL(alEffecti),
139     DECL(alEffectiv),
140     DECL(alGetEffectf),
141     DECL(alGetEffectfv),
142     DECL(alGetEffecti),
143     DECL(alGetEffectiv),
144     DECL(alGenAuxiliaryEffectSlots),
145     DECL(alDeleteAuxiliaryEffectSlots),
146     DECL(alIsAuxiliaryEffectSlot),
147     DECL(alAuxiliaryEffectSlotf),
148     DECL(alAuxiliaryEffectSlotfv),
149     DECL(alAuxiliaryEffectSloti),
150     DECL(alAuxiliaryEffectSlotiv),
151     DECL(alGetAuxiliaryEffectSlotf),
152     DECL(alGetAuxiliaryEffectSlotfv),
153     DECL(alGetAuxiliaryEffectSloti),
154     DECL(alGetAuxiliaryEffectSlotiv),
155 }};
156 #undef DECL
157 
158 #define DECL(x) { #x, (x) }
159 struct EnumExportEntry {
160     const ALCchar *enumName;
161     ALCenum value;
162 };
163 static const std::array<EnumExportEntry,92> alcEnumerations{{
164     DECL(ALC_INVALID),
165     DECL(ALC_FALSE),
166     DECL(ALC_TRUE),
167 
168     DECL(ALC_MAJOR_VERSION),
169     DECL(ALC_MINOR_VERSION),
170     DECL(ALC_ATTRIBUTES_SIZE),
171     DECL(ALC_ALL_ATTRIBUTES),
172     DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
173     DECL(ALC_DEVICE_SPECIFIER),
174     DECL(ALC_ALL_DEVICES_SPECIFIER),
175     DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
176     DECL(ALC_EXTENSIONS),
177     DECL(ALC_FREQUENCY),
178     DECL(ALC_REFRESH),
179     DECL(ALC_SYNC),
180     DECL(ALC_MONO_SOURCES),
181     DECL(ALC_STEREO_SOURCES),
182     DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
183     DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
184     DECL(ALC_CAPTURE_SAMPLES),
185 
186     DECL(ALC_NO_ERROR),
187     DECL(ALC_INVALID_DEVICE),
188     DECL(ALC_INVALID_CONTEXT),
189     DECL(ALC_INVALID_ENUM),
190     DECL(ALC_INVALID_VALUE),
191     DECL(ALC_OUT_OF_MEMORY),
192 
193     DECL(AL_INVALID),
194     DECL(AL_NONE),
195     DECL(AL_FALSE),
196     DECL(AL_TRUE),
197 
198     DECL(AL_SOURCE_RELATIVE),
199     DECL(AL_CONE_INNER_ANGLE),
200     DECL(AL_CONE_OUTER_ANGLE),
201     DECL(AL_PITCH),
202     DECL(AL_POSITION),
203     DECL(AL_DIRECTION),
204     DECL(AL_VELOCITY),
205     DECL(AL_LOOPING),
206     DECL(AL_BUFFER),
207     DECL(AL_GAIN),
208     DECL(AL_MIN_GAIN),
209     DECL(AL_MAX_GAIN),
210     DECL(AL_ORIENTATION),
211     DECL(AL_REFERENCE_DISTANCE),
212     DECL(AL_ROLLOFF_FACTOR),
213     DECL(AL_CONE_OUTER_GAIN),
214     DECL(AL_MAX_DISTANCE),
215     DECL(AL_SEC_OFFSET),
216     DECL(AL_SAMPLE_OFFSET),
217     DECL(AL_BYTE_OFFSET),
218     DECL(AL_SOURCE_TYPE),
219     DECL(AL_STATIC),
220     DECL(AL_STREAMING),
221     DECL(AL_UNDETERMINED),
222 
223     DECL(AL_SOURCE_STATE),
224     DECL(AL_INITIAL),
225     DECL(AL_PLAYING),
226     DECL(AL_PAUSED),
227     DECL(AL_STOPPED),
228 
229     DECL(AL_BUFFERS_QUEUED),
230     DECL(AL_BUFFERS_PROCESSED),
231 
232     DECL(AL_FORMAT_MONO8),
233     DECL(AL_FORMAT_MONO16),
234     DECL(AL_FORMAT_STEREO8),
235     DECL(AL_FORMAT_STEREO16),
236 
237     DECL(AL_FREQUENCY),
238     DECL(AL_BITS),
239     DECL(AL_CHANNELS),
240     DECL(AL_SIZE),
241 
242     DECL(AL_UNUSED),
243     DECL(AL_PENDING),
244     DECL(AL_PROCESSED),
245 
246     DECL(AL_NO_ERROR),
247     DECL(AL_INVALID_NAME),
248     DECL(AL_INVALID_ENUM),
249     DECL(AL_INVALID_VALUE),
250     DECL(AL_INVALID_OPERATION),
251     DECL(AL_OUT_OF_MEMORY),
252 
253     DECL(AL_VENDOR),
254     DECL(AL_VERSION),
255     DECL(AL_RENDERER),
256     DECL(AL_EXTENSIONS),
257 
258     DECL(AL_DOPPLER_FACTOR),
259     DECL(AL_DOPPLER_VELOCITY),
260     DECL(AL_DISTANCE_MODEL),
261     DECL(AL_SPEED_OF_SOUND),
262 
263     DECL(AL_INVERSE_DISTANCE),
264     DECL(AL_INVERSE_DISTANCE_CLAMPED),
265     DECL(AL_LINEAR_DISTANCE),
266     DECL(AL_LINEAR_DISTANCE_CLAMPED),
267     DECL(AL_EXPONENT_DISTANCE),
268     DECL(AL_EXPONENT_DISTANCE_CLAMPED),
269 }};
270 #undef DECL
271 
272 static const ALCchar alcNoError[] = "No Error";
273 static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
274 static const ALCchar alcErrInvalidContext[] = "Invalid Context";
275 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
276 static const ALCchar alcErrInvalidValue[] = "Invalid Value";
277 static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
278 static const ALCchar alcExtensionList[] =
279     "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
280     "ALC_EXT_thread_local_context";
281 
282 static const ALCint alcMajorVersion = 1;
283 static const ALCint alcMinorVersion = 1;
284 
285 
286 static std::recursive_mutex EnumerationLock;
287 static std::mutex ContextSwitchLock;
288 
289 static std::atomic<ALCenum> LastError{ALC_NO_ERROR};
290 static PtrIntMap DeviceIfaceMap;
291 static PtrIntMap ContextIfaceMap;
292 
293 
294 typedef struct EnumeratedList {
295     std::vector<ALCchar> Names;
296     std::vector<ALCint> Indicies;
297 
clearEnumeratedList298     void clear()
299     {
300         Names.clear();
301         Indicies.clear();
302     }
303 } EnumeratedList;
304 static EnumeratedList DevicesList;
305 static EnumeratedList AllDevicesList;
306 static EnumeratedList CaptureDevicesList;
307 
AppendDeviceList(EnumeratedList * list,const ALCchar * names,ALint idx)308 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
309 {
310     const ALCchar *name_end = names;
311     if(!name_end) return;
312 
313     ALCsizei count = 0;
314     while(*name_end)
315     {
316         TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
317         ++count;
318         name_end += strlen(name_end)+1;
319     }
320     if(names == name_end)
321         return;
322 
323     list->Names.reserve(list->Names.size() + (name_end - names) + 1);
324     list->Names.insert(list->Names.cend(), names, name_end);
325 
326     list->Indicies.reserve(list->Indicies.size() + count);
327     list->Indicies.insert(list->Indicies.cend(), count, idx);
328 }
329 
GetDriverIndexForName(const EnumeratedList * list,const ALCchar * name)330 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
331 {
332     const ALCchar *devnames = list->Names.data();
333     const ALCint *index = list->Indicies.data();
334 
335     while(devnames && *devnames)
336     {
337         if(strcmp(name, devnames) == 0)
338             return *index;
339         devnames += strlen(devnames)+1;
340         index++;
341     }
342     return -1;
343 }
344 
345 
alcOpenDevice(const ALCchar * devicename)346 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
347 {
348     ALCdevice *device = nullptr;
349     ALint idx = 0;
350 
351     /* Prior to the enumeration extension, apps would hardcode these names as a
352      * quality hint for the wrapper driver. Ignore them since there's no sane
353      * way to map them.
354      */
355     if(devicename && (devicename[0] == '\0' ||
356                       strcmp(devicename, "DirectSound3D") == 0 ||
357                       strcmp(devicename, "DirectSound") == 0 ||
358                       strcmp(devicename, "MMSYSTEM") == 0))
359         devicename = nullptr;
360     if(devicename)
361     {
362         {
363             std::lock_guard<std::recursive_mutex> _{EnumerationLock};
364             if(DevicesList.Names.empty())
365                 (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
366             idx = GetDriverIndexForName(&DevicesList, devicename);
367             if(idx < 0)
368             {
369                 if(AllDevicesList.Names.empty())
370                     (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
371                 idx = GetDriverIndexForName(&AllDevicesList, devicename);
372             }
373         }
374 
375         if(idx < 0)
376         {
377             LastError.store(ALC_INVALID_VALUE);
378             TRACE("Failed to find driver for name \"%s\"\n", devicename);
379             return nullptr;
380         }
381         TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
382         device = DriverList[idx].alcOpenDevice(devicename);
383     }
384     else
385     {
386         for(const auto &drv : DriverList)
387         {
388             if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
389                drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
390             {
391                 TRACE("Using default device from driver %d\n", idx);
392                 device = drv.alcOpenDevice(nullptr);
393                 break;
394             }
395             ++idx;
396         }
397     }
398 
399     if(device)
400     {
401         if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
402         {
403             DriverList[idx].alcCloseDevice(device);
404             device = nullptr;
405         }
406     }
407 
408     return device;
409 }
410 
alcCloseDevice(ALCdevice * device)411 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
412 {
413     ALint idx;
414 
415     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
416     {
417         LastError.store(ALC_INVALID_DEVICE);
418         return ALC_FALSE;
419     }
420     if(!DriverList[idx].alcCloseDevice(device))
421         return ALC_FALSE;
422     DeviceIfaceMap.removeByKey(device);
423     return ALC_TRUE;
424 }
425 
426 
alcCreateContext(ALCdevice * device,const ALCint * attrlist)427 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
428 {
429     ALCcontext *context;
430     ALint idx;
431 
432     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
433     {
434         LastError.store(ALC_INVALID_DEVICE);
435         return nullptr;
436     }
437     context = DriverList[idx].alcCreateContext(device, attrlist);
438     if(context)
439     {
440         if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
441         {
442             DriverList[idx].alcDestroyContext(context);
443             context = nullptr;
444         }
445     }
446 
447     return context;
448 }
449 
alcMakeContextCurrent(ALCcontext * context)450 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
451 {
452     ALint idx = -1;
453 
454     std::lock_guard<std::mutex> _{ContextSwitchLock};
455     if(context)
456     {
457         idx = ContextIfaceMap.lookupByKey(context);
458         if(idx < 0)
459         {
460             LastError.store(ALC_INVALID_CONTEXT);
461             return ALC_FALSE;
462         }
463         if(!DriverList[idx].alcMakeContextCurrent(context))
464             return ALC_FALSE;
465     }
466 
467     /* Unset the context from the old driver if it's different from the new
468      * current one.
469      */
470     if(idx < 0)
471     {
472         DriverIface *oldiface = ThreadCtxDriver;
473         if(oldiface) oldiface->alcSetThreadContext(nullptr);
474         oldiface = CurrentCtxDriver.exchange(nullptr);
475         if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
476     }
477     else
478     {
479         DriverIface *oldiface = ThreadCtxDriver;
480         if(oldiface && oldiface != &DriverList[idx])
481             oldiface->alcSetThreadContext(nullptr);
482         oldiface = CurrentCtxDriver.exchange(&DriverList[idx]);
483         if(oldiface && oldiface != &DriverList[idx])
484             oldiface->alcMakeContextCurrent(nullptr);
485     }
486     ThreadCtxDriver = nullptr;
487 
488     return ALC_TRUE;
489 }
490 
alcProcessContext(ALCcontext * context)491 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
492 {
493     if(context)
494     {
495         ALint idx = ContextIfaceMap.lookupByKey(context);
496         if(idx >= 0)
497             return DriverList[idx].alcProcessContext(context);
498     }
499     LastError.store(ALC_INVALID_CONTEXT);
500 }
501 
alcSuspendContext(ALCcontext * context)502 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
503 {
504     if(context)
505     {
506         ALint idx = ContextIfaceMap.lookupByKey(context);
507         if(idx >= 0)
508             return DriverList[idx].alcSuspendContext(context);
509     }
510     LastError.store(ALC_INVALID_CONTEXT);
511 }
512 
alcDestroyContext(ALCcontext * context)513 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
514 {
515     ALint idx;
516 
517     if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
518     {
519         LastError.store(ALC_INVALID_CONTEXT);
520         return;
521     }
522 
523     DriverList[idx].alcDestroyContext(context);
524     ContextIfaceMap.removeByKey(context);
525 }
526 
alcGetCurrentContext(void)527 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
528 {
529     DriverIface *iface = ThreadCtxDriver;
530     if(!iface) iface = CurrentCtxDriver.load();
531     return iface ? iface->alcGetCurrentContext() : nullptr;
532 }
533 
alcGetContextsDevice(ALCcontext * context)534 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
535 {
536     if(context)
537     {
538         ALint idx = ContextIfaceMap.lookupByKey(context);
539         if(idx >= 0)
540             return DriverList[idx].alcGetContextsDevice(context);
541     }
542     LastError.store(ALC_INVALID_CONTEXT);
543     return nullptr;
544 }
545 
546 
alcGetError(ALCdevice * device)547 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
548 {
549     if(device)
550     {
551         ALint idx = DeviceIfaceMap.lookupByKey(device);
552         if(idx < 0) return ALC_INVALID_DEVICE;
553         return DriverList[idx].alcGetError(device);
554     }
555     return LastError.exchange(ALC_NO_ERROR);
556 }
557 
alcIsExtensionPresent(ALCdevice * device,const ALCchar * extname)558 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
559 {
560     const char *ptr;
561     size_t len;
562 
563     if(device)
564     {
565         ALint idx = DeviceIfaceMap.lookupByKey(device);
566         if(idx < 0)
567         {
568             LastError.store(ALC_INVALID_DEVICE);
569             return ALC_FALSE;
570         }
571         return DriverList[idx].alcIsExtensionPresent(device, extname);
572     }
573 
574     len = strlen(extname);
575     ptr = alcExtensionList;
576     while(ptr && *ptr)
577     {
578         if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
579             return ALC_TRUE;
580         if((ptr=strchr(ptr, ' ')) != nullptr)
581         {
582             do {
583                 ++ptr;
584             } while(isspace(*ptr));
585         }
586     }
587     return ALC_FALSE;
588 }
589 
alcGetProcAddress(ALCdevice * device,const ALCchar * funcname)590 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
591 {
592     if(device)
593     {
594         ALint idx = DeviceIfaceMap.lookupByKey(device);
595         if(idx < 0)
596         {
597             LastError.store(ALC_INVALID_DEVICE);
598             return nullptr;
599         }
600         return DriverList[idx].alcGetProcAddress(device, funcname);
601     }
602 
603     auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
604         [funcname](const FuncExportEntry &entry) -> bool
605         { return strcmp(funcname, entry.funcName) == 0; }
606     );
607     return (iter != alcFunctions.cend()) ? iter->address : nullptr;
608 }
609 
alcGetEnumValue(ALCdevice * device,const ALCchar * enumname)610 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
611 {
612     if(device)
613     {
614         ALint idx = DeviceIfaceMap.lookupByKey(device);
615         if(idx < 0)
616         {
617             LastError.store(ALC_INVALID_DEVICE);
618             return 0;
619         }
620         return DriverList[idx].alcGetEnumValue(device, enumname);
621     }
622 
623     auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
624         [enumname](const EnumExportEntry &entry) -> bool
625         { return strcmp(enumname, entry.enumName) == 0; }
626     );
627     return (iter != alcEnumerations.cend()) ? iter->value : 0;
628 }
629 
alcGetString(ALCdevice * device,ALCenum param)630 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
631 {
632     if(device)
633     {
634         ALint idx = DeviceIfaceMap.lookupByKey(device);
635         if(idx < 0)
636         {
637             LastError.store(ALC_INVALID_DEVICE);
638             return nullptr;
639         }
640         return DriverList[idx].alcGetString(device, param);
641     }
642 
643     switch(param)
644     {
645     case ALC_NO_ERROR:
646         return alcNoError;
647     case ALC_INVALID_ENUM:
648         return alcErrInvalidEnum;
649     case ALC_INVALID_VALUE:
650         return alcErrInvalidValue;
651     case ALC_INVALID_DEVICE:
652         return alcErrInvalidDevice;
653     case ALC_INVALID_CONTEXT:
654         return alcErrInvalidContext;
655     case ALC_OUT_OF_MEMORY:
656         return alcErrOutOfMemory;
657     case ALC_EXTENSIONS:
658         return alcExtensionList;
659 
660     case ALC_DEVICE_SPECIFIER:
661     {
662         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
663         DevicesList.clear();
664         ALint idx{0};
665         for(const auto &drv : DriverList)
666         {
667             /* Only enumerate names from drivers that support it. */
668             if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
669                 || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
670                 AppendDeviceList(&DevicesList,
671                     drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
672             ++idx;
673         }
674         /* Ensure the list is double-null termianted. */
675         if(DevicesList.Names.empty())
676             DevicesList.Names.emplace_back('\0');
677         DevicesList.Names.emplace_back('\0');
678         return DevicesList.Names.data();
679     }
680 
681     case ALC_ALL_DEVICES_SPECIFIER:
682     {
683         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
684         AllDevicesList.clear();
685         ALint idx{0};
686         for(const auto &drv : DriverList)
687         {
688             /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
689              * standard enumeration.
690              */
691             if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
692                 AppendDeviceList(&AllDevicesList,
693                     drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx);
694             else if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
695                 || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
696                 AppendDeviceList(&AllDevicesList,
697                     drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
698             ++idx;
699         }
700         /* Ensure the list is double-null termianted. */
701         if(AllDevicesList.Names.empty())
702             AllDevicesList.Names.emplace_back('\0');
703         AllDevicesList.Names.emplace_back('\0');
704         return AllDevicesList.Names.data();
705     }
706 
707     case ALC_CAPTURE_DEVICE_SPECIFIER:
708     {
709         std::lock_guard<std::recursive_mutex> _{EnumerationLock};
710         CaptureDevicesList.clear();
711         ALint idx{0};
712         for(const auto &drv : DriverList)
713         {
714             if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
715                 || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
716                 AppendDeviceList(&CaptureDevicesList,
717                     drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx);
718             ++idx;
719         }
720         /* Ensure the list is double-null termianted. */
721         if(CaptureDevicesList.Names.empty())
722             CaptureDevicesList.Names.emplace_back('\0');
723         CaptureDevicesList.Names.emplace_back('\0');
724         return CaptureDevicesList.Names.data();
725     }
726 
727     case ALC_DEFAULT_DEVICE_SPECIFIER:
728     {
729         auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
730             [](const DriverIface &drv) -> bool
731             {
732                 return drv.ALCVer >= MAKE_ALC_VER(1, 1)
733                     || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT");
734             }
735         );
736         if(iter != DriverList.cend())
737             return iter->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
738         return "";
739     }
740 
741     case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
742     {
743         auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
744             [](const DriverIface &drv) -> bool
745             { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; });
746         if(iter != DriverList.cend())
747             return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
748         return "";
749     }
750 
751     case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
752     {
753         auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
754             [](const DriverIface &drv) -> bool
755             {
756                 return drv.ALCVer >= MAKE_ALC_VER(1, 1)
757                     || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
758             }
759         );
760         if(iter != DriverList.cend())
761             return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
762         return "";
763     }
764 
765     default:
766         LastError.store(ALC_INVALID_ENUM);
767         break;
768     }
769     return nullptr;
770 }
771 
alcGetIntegerv(ALCdevice * device,ALCenum param,ALCsizei size,ALCint * values)772 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
773 {
774     if(device)
775     {
776         ALint idx = DeviceIfaceMap.lookupByKey(device);
777         if(idx < 0)
778         {
779             LastError.store(ALC_INVALID_DEVICE);
780             return;
781         }
782         return DriverList[idx].alcGetIntegerv(device, param, size, values);
783     }
784 
785     if(size <= 0 || values == nullptr)
786     {
787         LastError.store(ALC_INVALID_VALUE);
788         return;
789     }
790 
791     switch(param)
792     {
793         case ALC_MAJOR_VERSION:
794             if(size >= 1)
795             {
796                 values[0] = alcMajorVersion;
797                 return;
798             }
799             /*fall-through*/
800         case ALC_MINOR_VERSION:
801             if(size >= 1)
802             {
803                 values[0] = alcMinorVersion;
804                 return;
805             }
806             LastError.store(ALC_INVALID_VALUE);
807             return;
808 
809         case ALC_ATTRIBUTES_SIZE:
810         case ALC_ALL_ATTRIBUTES:
811         case ALC_FREQUENCY:
812         case ALC_REFRESH:
813         case ALC_SYNC:
814         case ALC_MONO_SOURCES:
815         case ALC_STEREO_SOURCES:
816         case ALC_CAPTURE_SAMPLES:
817             LastError.store(ALC_INVALID_DEVICE);
818             return;
819 
820         default:
821             LastError.store(ALC_INVALID_ENUM);
822             return;
823     }
824 }
825 
826 
alcCaptureOpenDevice(const ALCchar * devicename,ALCuint frequency,ALCenum format,ALCsizei buffersize)827 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
828 {
829     ALCdevice *device = nullptr;
830     ALint idx = 0;
831 
832     if(devicename && devicename[0] == '\0')
833         devicename = nullptr;
834     if(devicename)
835     {
836         {
837             std::lock_guard<std::recursive_mutex> _{EnumerationLock};
838             if(CaptureDevicesList.Names.empty())
839                 (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
840             idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
841         }
842 
843         if(idx < 0)
844         {
845             LastError.store(ALC_INVALID_VALUE);
846             TRACE("Failed to find driver for name \"%s\"\n", devicename);
847             return nullptr;
848         }
849         TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
850         device = DriverList[idx].alcCaptureOpenDevice(devicename, frequency, format, buffersize);
851     }
852     else
853     {
854         for(const auto &drv : DriverList)
855         {
856             if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
857                 || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
858             {
859                 TRACE("Using default capture device from driver %d\n", idx);
860                 device = drv.alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
861                 break;
862             }
863             ++idx;
864         }
865     }
866 
867     if(device)
868     {
869         if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
870         {
871             DriverList[idx].alcCaptureCloseDevice(device);
872             device = nullptr;
873         }
874     }
875 
876     return device;
877 }
878 
alcCaptureCloseDevice(ALCdevice * device)879 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
880 {
881     ALint idx;
882 
883     if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
884     {
885         LastError.store(ALC_INVALID_DEVICE);
886         return ALC_FALSE;
887     }
888     if(!DriverList[idx].alcCaptureCloseDevice(device))
889         return ALC_FALSE;
890     DeviceIfaceMap.removeByKey(device);
891     return ALC_TRUE;
892 }
893 
alcCaptureStart(ALCdevice * device)894 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
895 {
896     if(device)
897     {
898         ALint idx = DeviceIfaceMap.lookupByKey(device);
899         if(idx >= 0)
900             return DriverList[idx].alcCaptureStart(device);
901     }
902     LastError.store(ALC_INVALID_DEVICE);
903 }
904 
alcCaptureStop(ALCdevice * device)905 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
906 {
907     if(device)
908     {
909         ALint idx = DeviceIfaceMap.lookupByKey(device);
910         if(idx >= 0)
911             return DriverList[idx].alcCaptureStop(device);
912     }
913     LastError.store(ALC_INVALID_DEVICE);
914 }
915 
alcCaptureSamples(ALCdevice * device,ALCvoid * buffer,ALCsizei samples)916 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
917 {
918     if(device)
919     {
920         ALint idx = DeviceIfaceMap.lookupByKey(device);
921         if(idx >= 0)
922             return DriverList[idx].alcCaptureSamples(device, buffer, samples);
923     }
924     LastError.store(ALC_INVALID_DEVICE);
925 }
926 
927 
alcSetThreadContext(ALCcontext * context)928 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
929 {
930     ALCenum err = ALC_INVALID_CONTEXT;
931     ALint idx;
932 
933     if(!context)
934     {
935         DriverIface *oldiface = ThreadCtxDriver;
936         if(oldiface && !oldiface->alcSetThreadContext(nullptr))
937             return ALC_FALSE;
938         ThreadCtxDriver = nullptr;
939         return ALC_TRUE;
940     }
941 
942     idx = ContextIfaceMap.lookupByKey(context);
943     if(idx >= 0)
944     {
945         if(DriverList[idx].alcSetThreadContext(context))
946         {
947             DriverIface *oldiface = ThreadCtxDriver;
948             if(oldiface != &DriverList[idx])
949             {
950                 ThreadCtxDriver = &DriverList[idx];
951                 if(oldiface) oldiface->alcSetThreadContext(nullptr);
952             }
953             return ALC_TRUE;
954         }
955         err = DriverList[idx].alcGetError(nullptr);
956     }
957     LastError.store(err);
958     return ALC_FALSE;
959 }
960 
alcGetThreadContext(void)961 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
962 {
963     DriverIface *iface = ThreadCtxDriver;
964     if(iface) return iface->alcGetThreadContext();
965     return nullptr;
966 }
967