Add options to reverse local X and Y coordinates
[openal-soft.git] / router / alc.cpp
blob210f683e0975f8e57fb48211c81a7593fe918055
2 #include "config.h"
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
9 #include <mutex>
10 #include <algorithm>
11 #include <array>
13 #include "AL/alc.h"
14 #include "alstring.h"
15 #include "router.h"
18 #define DECL(x) { #x, reinterpret_cast<void*>(x) }
19 struct FuncExportEntry {
20 const char *funcName;
21 void *address;
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),
45 DECL(alcSetThreadContext),
46 DECL(alcGetThreadContext),
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),
122 #undef DECL
124 #define DECL(x) { #x, (x) }
125 struct EnumExportEntry {
126 const ALCchar *enumName;
127 ALCenum value;
129 static const std::array<EnumExportEntry,92> alcEnumerations{{
130 DECL(ALC_INVALID),
131 DECL(ALC_FALSE),
132 DECL(ALC_TRUE),
134 DECL(ALC_MAJOR_VERSION),
135 DECL(ALC_MINOR_VERSION),
136 DECL(ALC_ATTRIBUTES_SIZE),
137 DECL(ALC_ALL_ATTRIBUTES),
138 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
139 DECL(ALC_DEVICE_SPECIFIER),
140 DECL(ALC_ALL_DEVICES_SPECIFIER),
141 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
142 DECL(ALC_EXTENSIONS),
143 DECL(ALC_FREQUENCY),
144 DECL(ALC_REFRESH),
145 DECL(ALC_SYNC),
146 DECL(ALC_MONO_SOURCES),
147 DECL(ALC_STEREO_SOURCES),
148 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
149 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
150 DECL(ALC_CAPTURE_SAMPLES),
152 DECL(ALC_NO_ERROR),
153 DECL(ALC_INVALID_DEVICE),
154 DECL(ALC_INVALID_CONTEXT),
155 DECL(ALC_INVALID_ENUM),
156 DECL(ALC_INVALID_VALUE),
157 DECL(ALC_OUT_OF_MEMORY),
159 DECL(AL_INVALID),
160 DECL(AL_NONE),
161 DECL(AL_FALSE),
162 DECL(AL_TRUE),
164 DECL(AL_SOURCE_RELATIVE),
165 DECL(AL_CONE_INNER_ANGLE),
166 DECL(AL_CONE_OUTER_ANGLE),
167 DECL(AL_PITCH),
168 DECL(AL_POSITION),
169 DECL(AL_DIRECTION),
170 DECL(AL_VELOCITY),
171 DECL(AL_LOOPING),
172 DECL(AL_BUFFER),
173 DECL(AL_GAIN),
174 DECL(AL_MIN_GAIN),
175 DECL(AL_MAX_GAIN),
176 DECL(AL_ORIENTATION),
177 DECL(AL_REFERENCE_DISTANCE),
178 DECL(AL_ROLLOFF_FACTOR),
179 DECL(AL_CONE_OUTER_GAIN),
180 DECL(AL_MAX_DISTANCE),
181 DECL(AL_SEC_OFFSET),
182 DECL(AL_SAMPLE_OFFSET),
183 DECL(AL_BYTE_OFFSET),
184 DECL(AL_SOURCE_TYPE),
185 DECL(AL_STATIC),
186 DECL(AL_STREAMING),
187 DECL(AL_UNDETERMINED),
189 DECL(AL_SOURCE_STATE),
190 DECL(AL_INITIAL),
191 DECL(AL_PLAYING),
192 DECL(AL_PAUSED),
193 DECL(AL_STOPPED),
195 DECL(AL_BUFFERS_QUEUED),
196 DECL(AL_BUFFERS_PROCESSED),
198 DECL(AL_FORMAT_MONO8),
199 DECL(AL_FORMAT_MONO16),
200 DECL(AL_FORMAT_STEREO8),
201 DECL(AL_FORMAT_STEREO16),
203 DECL(AL_FREQUENCY),
204 DECL(AL_BITS),
205 DECL(AL_CHANNELS),
206 DECL(AL_SIZE),
208 DECL(AL_UNUSED),
209 DECL(AL_PENDING),
210 DECL(AL_PROCESSED),
212 DECL(AL_NO_ERROR),
213 DECL(AL_INVALID_NAME),
214 DECL(AL_INVALID_ENUM),
215 DECL(AL_INVALID_VALUE),
216 DECL(AL_INVALID_OPERATION),
217 DECL(AL_OUT_OF_MEMORY),
219 DECL(AL_VENDOR),
220 DECL(AL_VERSION),
221 DECL(AL_RENDERER),
222 DECL(AL_EXTENSIONS),
224 DECL(AL_DOPPLER_FACTOR),
225 DECL(AL_DOPPLER_VELOCITY),
226 DECL(AL_DISTANCE_MODEL),
227 DECL(AL_SPEED_OF_SOUND),
229 DECL(AL_INVERSE_DISTANCE),
230 DECL(AL_INVERSE_DISTANCE_CLAMPED),
231 DECL(AL_LINEAR_DISTANCE),
232 DECL(AL_LINEAR_DISTANCE_CLAMPED),
233 DECL(AL_EXPONENT_DISTANCE),
234 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
236 #undef DECL
238 static const ALCchar alcNoError[] = "No Error";
239 static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
240 static const ALCchar alcErrInvalidContext[] = "Invalid Context";
241 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
242 static const ALCchar alcErrInvalidValue[] = "Invalid Value";
243 static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
244 static const ALCchar alcExtensionList[] =
245 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
246 "ALC_EXT_thread_local_context";
248 static const ALCint alcMajorVersion = 1;
249 static const ALCint alcMinorVersion = 1;
252 static std::recursive_mutex EnumerationLock;
253 static std::mutex ContextSwitchLock;
255 static std::atomic<ALCenum> LastError{ALC_NO_ERROR};
256 static PtrIntMap DeviceIfaceMap;
257 static PtrIntMap ContextIfaceMap;
260 typedef struct EnumeratedList {
261 std::vector<ALCchar> Names;
262 std::vector<ALCint> Indicies;
264 void clear()
266 Names.clear();
267 Indicies.clear();
269 } EnumeratedList;
270 static EnumeratedList DevicesList;
271 static EnumeratedList AllDevicesList;
272 static EnumeratedList CaptureDevicesList;
274 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
276 const ALCchar *name_end = names;
277 if(!name_end) return;
279 ALCsizei count = 0;
280 while(*name_end)
282 TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
283 ++count;
284 name_end += strlen(name_end)+1;
286 if(names == name_end)
287 return;
289 list->Names.reserve(list->Names.size() + (name_end - names) + 1);
290 list->Names.insert(list->Names.cend(), names, name_end);
292 list->Indicies.reserve(list->Indicies.size() + count);
293 list->Indicies.insert(list->Indicies.cend(), count, idx);
296 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
298 const ALCchar *devnames = list->Names.data();
299 const ALCint *index = list->Indicies.data();
301 while(devnames && *devnames)
303 if(strcmp(name, devnames) == 0)
304 return *index;
305 devnames += strlen(devnames)+1;
306 index++;
308 return -1;
312 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
314 ALCdevice *device = nullptr;
315 ALint idx = 0;
317 /* Prior to the enumeration extension, apps would hardcode these names as a
318 * quality hint for the wrapper driver. Ignore them since there's no sane
319 * way to map them.
321 if(devicename && (devicename[0] == '\0' ||
322 strcmp(devicename, "DirectSound3D") == 0 ||
323 strcmp(devicename, "DirectSound") == 0 ||
324 strcmp(devicename, "MMSYSTEM") == 0))
325 devicename = nullptr;
326 if(devicename)
329 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
330 if(DevicesList.Names.empty())
331 (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
332 idx = GetDriverIndexForName(&DevicesList, devicename);
333 if(idx < 0)
335 if(AllDevicesList.Names.empty())
336 (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
337 idx = GetDriverIndexForName(&AllDevicesList, devicename);
341 if(idx < 0)
343 LastError.store(ALC_INVALID_VALUE);
344 TRACE("Failed to find driver for name \"%s\"\n", devicename);
345 return nullptr;
347 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
348 device = DriverList[idx].alcOpenDevice(devicename);
350 else
352 for(const auto &drv : DriverList)
354 if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
355 drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
357 TRACE("Using default device from driver %d\n", idx);
358 device = drv.alcOpenDevice(nullptr);
359 break;
361 ++idx;
365 if(device)
367 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
369 DriverList[idx].alcCloseDevice(device);
370 device = nullptr;
374 return device;
377 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
379 ALint idx;
381 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
383 LastError.store(ALC_INVALID_DEVICE);
384 return ALC_FALSE;
386 if(!DriverList[idx].alcCloseDevice(device))
387 return ALC_FALSE;
388 DeviceIfaceMap.removeByKey(device);
389 return ALC_TRUE;
393 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
395 ALCcontext *context;
396 ALint idx;
398 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
400 LastError.store(ALC_INVALID_DEVICE);
401 return nullptr;
403 context = DriverList[idx].alcCreateContext(device, attrlist);
404 if(context)
406 if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
408 DriverList[idx].alcDestroyContext(context);
409 context = nullptr;
413 return context;
416 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
418 ALint idx = -1;
420 std::lock_guard<std::mutex> _{ContextSwitchLock};
421 if(context)
423 idx = ContextIfaceMap.lookupByKey(context);
424 if(idx < 0)
426 LastError.store(ALC_INVALID_CONTEXT);
427 return ALC_FALSE;
429 if(!DriverList[idx].alcMakeContextCurrent(context))
430 return ALC_FALSE;
433 /* Unset the context from the old driver if it's different from the new
434 * current one.
436 if(idx < 0)
438 DriverIface *oldiface = GetThreadDriver();
439 if(oldiface) oldiface->alcSetThreadContext(nullptr);
440 oldiface = CurrentCtxDriver.exchange(nullptr);
441 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
443 else
445 DriverIface *oldiface = GetThreadDriver();
446 if(oldiface && oldiface != &DriverList[idx])
447 oldiface->alcSetThreadContext(nullptr);
448 oldiface = CurrentCtxDriver.exchange(&DriverList[idx]);
449 if(oldiface && oldiface != &DriverList[idx])
450 oldiface->alcMakeContextCurrent(nullptr);
452 SetThreadDriver(nullptr);
454 return ALC_TRUE;
457 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
459 if(context)
461 ALint idx = ContextIfaceMap.lookupByKey(context);
462 if(idx >= 0)
463 return DriverList[idx].alcProcessContext(context);
465 LastError.store(ALC_INVALID_CONTEXT);
468 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
470 if(context)
472 ALint idx = ContextIfaceMap.lookupByKey(context);
473 if(idx >= 0)
474 return DriverList[idx].alcSuspendContext(context);
476 LastError.store(ALC_INVALID_CONTEXT);
479 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
481 ALint idx;
483 if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
485 LastError.store(ALC_INVALID_CONTEXT);
486 return;
489 DriverList[idx].alcDestroyContext(context);
490 ContextIfaceMap.removeByKey(context);
493 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
495 DriverIface *iface = GetThreadDriver();
496 if(!iface) iface = CurrentCtxDriver.load();
497 return iface ? iface->alcGetCurrentContext() : nullptr;
500 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
502 if(context)
504 ALint idx = ContextIfaceMap.lookupByKey(context);
505 if(idx >= 0)
506 return DriverList[idx].alcGetContextsDevice(context);
508 LastError.store(ALC_INVALID_CONTEXT);
509 return nullptr;
513 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
515 if(device)
517 ALint idx = DeviceIfaceMap.lookupByKey(device);
518 if(idx < 0) return ALC_INVALID_DEVICE;
519 return DriverList[idx].alcGetError(device);
521 return LastError.exchange(ALC_NO_ERROR);
524 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
526 const char *ptr;
527 size_t len;
529 if(device)
531 ALint idx = DeviceIfaceMap.lookupByKey(device);
532 if(idx < 0)
534 LastError.store(ALC_INVALID_DEVICE);
535 return ALC_FALSE;
537 return DriverList[idx].alcIsExtensionPresent(device, extname);
540 len = strlen(extname);
541 ptr = alcExtensionList;
542 while(ptr && *ptr)
544 if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
545 return ALC_TRUE;
546 if((ptr=strchr(ptr, ' ')) != nullptr)
548 do {
549 ++ptr;
550 } while(isspace(*ptr));
553 return ALC_FALSE;
556 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
558 if(device)
560 ALint idx = DeviceIfaceMap.lookupByKey(device);
561 if(idx < 0)
563 LastError.store(ALC_INVALID_DEVICE);
564 return nullptr;
566 return DriverList[idx].alcGetProcAddress(device, funcname);
569 auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
570 [funcname](const FuncExportEntry &entry) -> bool
571 { return strcmp(funcname, entry.funcName) == 0; }
573 return (iter != alcFunctions.cend()) ? iter->address : nullptr;
576 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
578 if(device)
580 ALint idx = DeviceIfaceMap.lookupByKey(device);
581 if(idx < 0)
583 LastError.store(ALC_INVALID_DEVICE);
584 return 0;
586 return DriverList[idx].alcGetEnumValue(device, enumname);
589 auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
590 [enumname](const EnumExportEntry &entry) -> bool
591 { return strcmp(enumname, entry.enumName) == 0; }
593 return (iter != alcEnumerations.cend()) ? iter->value : 0;
596 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
598 if(device)
600 ALint idx = DeviceIfaceMap.lookupByKey(device);
601 if(idx < 0)
603 LastError.store(ALC_INVALID_DEVICE);
604 return nullptr;
606 return DriverList[idx].alcGetString(device, param);
609 switch(param)
611 case ALC_NO_ERROR:
612 return alcNoError;
613 case ALC_INVALID_ENUM:
614 return alcErrInvalidEnum;
615 case ALC_INVALID_VALUE:
616 return alcErrInvalidValue;
617 case ALC_INVALID_DEVICE:
618 return alcErrInvalidDevice;
619 case ALC_INVALID_CONTEXT:
620 return alcErrInvalidContext;
621 case ALC_OUT_OF_MEMORY:
622 return alcErrOutOfMemory;
623 case ALC_EXTENSIONS:
624 return alcExtensionList;
626 case ALC_DEVICE_SPECIFIER:
628 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
629 DevicesList.clear();
630 ALint idx{0};
631 for(const auto &drv : DriverList)
633 /* Only enumerate names from drivers that support it. */
634 if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
635 || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
636 AppendDeviceList(&DevicesList,
637 drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
638 ++idx;
640 /* Ensure the list is double-null termianted. */
641 if(DevicesList.Names.empty())
642 DevicesList.Names.emplace_back('\0');
643 DevicesList.Names.emplace_back('\0');
644 return DevicesList.Names.data();
647 case ALC_ALL_DEVICES_SPECIFIER:
649 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
650 AllDevicesList.clear();
651 ALint idx{0};
652 for(const auto &drv : DriverList)
654 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
655 * standard enumeration.
657 if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
658 AppendDeviceList(&AllDevicesList,
659 drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx);
660 else if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
661 || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
662 AppendDeviceList(&AllDevicesList,
663 drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
664 ++idx;
666 /* Ensure the list is double-null termianted. */
667 if(AllDevicesList.Names.empty())
668 AllDevicesList.Names.emplace_back('\0');
669 AllDevicesList.Names.emplace_back('\0');
670 return AllDevicesList.Names.data();
673 case ALC_CAPTURE_DEVICE_SPECIFIER:
675 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
676 CaptureDevicesList.clear();
677 ALint idx{0};
678 for(const auto &drv : DriverList)
680 if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
681 || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
682 AppendDeviceList(&CaptureDevicesList,
683 drv.alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx);
684 ++idx;
686 /* Ensure the list is double-null termianted. */
687 if(CaptureDevicesList.Names.empty())
688 CaptureDevicesList.Names.emplace_back('\0');
689 CaptureDevicesList.Names.emplace_back('\0');
690 return CaptureDevicesList.Names.data();
693 case ALC_DEFAULT_DEVICE_SPECIFIER:
695 auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
696 [](const DriverIface &drv) -> bool
698 return drv.ALCVer >= MAKE_ALC_VER(1, 1)
699 || drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT");
702 if(iter != DriverList.cend())
703 return iter->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
704 return "";
707 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
709 auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
710 [](const DriverIface &drv) -> bool
711 { return drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE; });
712 if(iter != DriverList.cend())
713 return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
714 return "";
717 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
719 auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
720 [](const DriverIface &drv) -> bool
722 return drv.ALCVer >= MAKE_ALC_VER(1, 1)
723 || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
726 if(iter != DriverList.cend())
727 return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
728 return "";
731 default:
732 LastError.store(ALC_INVALID_ENUM);
733 break;
735 return nullptr;
738 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
740 if(device)
742 ALint idx = DeviceIfaceMap.lookupByKey(device);
743 if(idx < 0)
745 LastError.store(ALC_INVALID_DEVICE);
746 return;
748 return DriverList[idx].alcGetIntegerv(device, param, size, values);
751 if(size <= 0 || values == nullptr)
753 LastError.store(ALC_INVALID_VALUE);
754 return;
757 switch(param)
759 case ALC_MAJOR_VERSION:
760 if(size >= 1)
762 values[0] = alcMajorVersion;
763 return;
765 /*fall-through*/
766 case ALC_MINOR_VERSION:
767 if(size >= 1)
769 values[0] = alcMinorVersion;
770 return;
772 LastError.store(ALC_INVALID_VALUE);
773 return;
775 case ALC_ATTRIBUTES_SIZE:
776 case ALC_ALL_ATTRIBUTES:
777 case ALC_FREQUENCY:
778 case ALC_REFRESH:
779 case ALC_SYNC:
780 case ALC_MONO_SOURCES:
781 case ALC_STEREO_SOURCES:
782 case ALC_CAPTURE_SAMPLES:
783 LastError.store(ALC_INVALID_DEVICE);
784 return;
786 default:
787 LastError.store(ALC_INVALID_ENUM);
788 return;
793 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
795 ALCdevice *device = nullptr;
796 ALint idx = 0;
798 if(devicename && devicename[0] == '\0')
799 devicename = nullptr;
800 if(devicename)
803 std::lock_guard<std::recursive_mutex> _{EnumerationLock};
804 if(CaptureDevicesList.Names.empty())
805 (void)alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
806 idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
809 if(idx < 0)
811 LastError.store(ALC_INVALID_VALUE);
812 TRACE("Failed to find driver for name \"%s\"\n", devicename);
813 return nullptr;
815 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
816 device = DriverList[idx].alcCaptureOpenDevice(devicename, frequency, format, buffersize);
818 else
820 for(const auto &drv : DriverList)
822 if(drv.ALCVer >= MAKE_ALC_VER(1, 1)
823 || drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
825 TRACE("Using default capture device from driver %d\n", idx);
826 device = drv.alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
827 break;
829 ++idx;
833 if(device)
835 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
837 DriverList[idx].alcCaptureCloseDevice(device);
838 device = nullptr;
842 return device;
845 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
847 ALint idx;
849 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
851 LastError.store(ALC_INVALID_DEVICE);
852 return ALC_FALSE;
854 if(!DriverList[idx].alcCaptureCloseDevice(device))
855 return ALC_FALSE;
856 DeviceIfaceMap.removeByKey(device);
857 return ALC_TRUE;
860 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
862 if(device)
864 ALint idx = DeviceIfaceMap.lookupByKey(device);
865 if(idx >= 0)
866 return DriverList[idx].alcCaptureStart(device);
868 LastError.store(ALC_INVALID_DEVICE);
871 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
873 if(device)
875 ALint idx = DeviceIfaceMap.lookupByKey(device);
876 if(idx >= 0)
877 return DriverList[idx].alcCaptureStop(device);
879 LastError.store(ALC_INVALID_DEVICE);
882 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
884 if(device)
886 ALint idx = DeviceIfaceMap.lookupByKey(device);
887 if(idx >= 0)
888 return DriverList[idx].alcCaptureSamples(device, buffer, samples);
890 LastError.store(ALC_INVALID_DEVICE);
894 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
896 ALCenum err = ALC_INVALID_CONTEXT;
897 ALint idx;
899 if(!context)
901 DriverIface *oldiface = GetThreadDriver();
902 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
903 return ALC_FALSE;
904 SetThreadDriver(nullptr);
905 return ALC_TRUE;
908 idx = ContextIfaceMap.lookupByKey(context);
909 if(idx >= 0)
911 if(DriverList[idx].alcSetThreadContext(context))
913 DriverIface *oldiface = GetThreadDriver();
914 if(oldiface != &DriverList[idx])
916 SetThreadDriver(&DriverList[idx]);
917 if(oldiface) oldiface->alcSetThreadContext(nullptr);
919 return ALC_TRUE;
921 err = DriverList[idx].alcGetError(nullptr);
923 LastError.store(err);
924 return ALC_FALSE;
927 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
929 DriverIface *iface = GetThreadDriver();
930 if(iface) return iface->alcGetThreadContext();
931 return nullptr;