Avoid reference-to-function template parameters
[openal-soft.git] / router / alc.cpp
blob312ac6b736873324a93daba0f43391f1f711cc36
2 #include "config.h"
4 #include <algorithm>
5 #include <array>
6 #include <cstddef>
7 #include <cstdlib>
8 #include <cstring>
9 #include <cstdio>
10 #include <mutex>
11 #include <optional>
12 #include <string_view>
13 #include <tuple>
14 #include <unordered_map>
16 #include "AL/alc.h"
18 #include "almalloc.h"
19 #include "router.h"
22 namespace {
24 using namespace std::string_view_literals;
26 struct FuncExportEntry {
27 const char *funcName;
28 void *address;
30 #define DECL(x) FuncExportEntry{ #x, reinterpret_cast<void*>(x) }
31 const std::array alcFunctions{
32 DECL(alcCreateContext),
33 DECL(alcMakeContextCurrent),
34 DECL(alcProcessContext),
35 DECL(alcSuspendContext),
36 DECL(alcDestroyContext),
37 DECL(alcGetCurrentContext),
38 DECL(alcGetContextsDevice),
39 DECL(alcOpenDevice),
40 DECL(alcCloseDevice),
41 DECL(alcGetError),
42 DECL(alcIsExtensionPresent),
43 DECL(alcGetProcAddress),
44 DECL(alcGetEnumValue),
45 DECL(alcGetString),
46 DECL(alcGetIntegerv),
47 DECL(alcCaptureOpenDevice),
48 DECL(alcCaptureCloseDevice),
49 DECL(alcCaptureStart),
50 DECL(alcCaptureStop),
51 DECL(alcCaptureSamples),
53 DECL(alcSetThreadContext),
54 DECL(alcGetThreadContext),
56 DECL(alEnable),
57 DECL(alDisable),
58 DECL(alIsEnabled),
59 DECL(alGetString),
60 DECL(alGetBooleanv),
61 DECL(alGetIntegerv),
62 DECL(alGetFloatv),
63 DECL(alGetDoublev),
64 DECL(alGetBoolean),
65 DECL(alGetInteger),
66 DECL(alGetFloat),
67 DECL(alGetDouble),
68 DECL(alGetError),
69 DECL(alIsExtensionPresent),
70 DECL(alGetProcAddress),
71 DECL(alGetEnumValue),
72 DECL(alListenerf),
73 DECL(alListener3f),
74 DECL(alListenerfv),
75 DECL(alListeneri),
76 DECL(alListener3i),
77 DECL(alListeneriv),
78 DECL(alGetListenerf),
79 DECL(alGetListener3f),
80 DECL(alGetListenerfv),
81 DECL(alGetListeneri),
82 DECL(alGetListener3i),
83 DECL(alGetListeneriv),
84 DECL(alGenSources),
85 DECL(alDeleteSources),
86 DECL(alIsSource),
87 DECL(alSourcef),
88 DECL(alSource3f),
89 DECL(alSourcefv),
90 DECL(alSourcei),
91 DECL(alSource3i),
92 DECL(alSourceiv),
93 DECL(alGetSourcef),
94 DECL(alGetSource3f),
95 DECL(alGetSourcefv),
96 DECL(alGetSourcei),
97 DECL(alGetSource3i),
98 DECL(alGetSourceiv),
99 DECL(alSourcePlayv),
100 DECL(alSourceStopv),
101 DECL(alSourceRewindv),
102 DECL(alSourcePausev),
103 DECL(alSourcePlay),
104 DECL(alSourceStop),
105 DECL(alSourceRewind),
106 DECL(alSourcePause),
107 DECL(alSourceQueueBuffers),
108 DECL(alSourceUnqueueBuffers),
109 DECL(alGenBuffers),
110 DECL(alDeleteBuffers),
111 DECL(alIsBuffer),
112 DECL(alBufferData),
113 DECL(alBufferf),
114 DECL(alBuffer3f),
115 DECL(alBufferfv),
116 DECL(alBufferi),
117 DECL(alBuffer3i),
118 DECL(alBufferiv),
119 DECL(alGetBufferf),
120 DECL(alGetBuffer3f),
121 DECL(alGetBufferfv),
122 DECL(alGetBufferi),
123 DECL(alGetBuffer3i),
124 DECL(alGetBufferiv),
125 DECL(alDopplerFactor),
126 DECL(alDopplerVelocity),
127 DECL(alSpeedOfSound),
128 DECL(alDistanceModel),
130 /* EFX 1.0 */
131 DECL(alGenFilters),
132 DECL(alDeleteFilters),
133 DECL(alIsFilter),
134 DECL(alFilterf),
135 DECL(alFilterfv),
136 DECL(alFilteri),
137 DECL(alFilteriv),
138 DECL(alGetFilterf),
139 DECL(alGetFilterfv),
140 DECL(alGetFilteri),
141 DECL(alGetFilteriv),
142 DECL(alGenEffects),
143 DECL(alDeleteEffects),
144 DECL(alIsEffect),
145 DECL(alEffectf),
146 DECL(alEffectfv),
147 DECL(alEffecti),
148 DECL(alEffectiv),
149 DECL(alGetEffectf),
150 DECL(alGetEffectfv),
151 DECL(alGetEffecti),
152 DECL(alGetEffectiv),
153 DECL(alGenAuxiliaryEffectSlots),
154 DECL(alDeleteAuxiliaryEffectSlots),
155 DECL(alIsAuxiliaryEffectSlot),
156 DECL(alAuxiliaryEffectSlotf),
157 DECL(alAuxiliaryEffectSlotfv),
158 DECL(alAuxiliaryEffectSloti),
159 DECL(alAuxiliaryEffectSlotiv),
160 DECL(alGetAuxiliaryEffectSlotf),
161 DECL(alGetAuxiliaryEffectSlotfv),
162 DECL(alGetAuxiliaryEffectSloti),
163 DECL(alGetAuxiliaryEffectSlotiv),
165 #undef DECL
167 struct EnumExportEntry {
168 const ALCchar *enumName;
169 ALCenum value;
171 #define DECL(x) EnumExportEntry{ #x, (x) }
172 const std::array alcEnumerations{
173 DECL(ALC_INVALID),
174 DECL(ALC_FALSE),
175 DECL(ALC_TRUE),
177 DECL(ALC_MAJOR_VERSION),
178 DECL(ALC_MINOR_VERSION),
179 DECL(ALC_ATTRIBUTES_SIZE),
180 DECL(ALC_ALL_ATTRIBUTES),
181 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
182 DECL(ALC_DEVICE_SPECIFIER),
183 DECL(ALC_ALL_DEVICES_SPECIFIER),
184 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
185 DECL(ALC_EXTENSIONS),
186 DECL(ALC_FREQUENCY),
187 DECL(ALC_REFRESH),
188 DECL(ALC_SYNC),
189 DECL(ALC_MONO_SOURCES),
190 DECL(ALC_STEREO_SOURCES),
191 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
192 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
193 DECL(ALC_CAPTURE_SAMPLES),
195 DECL(ALC_NO_ERROR),
196 DECL(ALC_INVALID_DEVICE),
197 DECL(ALC_INVALID_CONTEXT),
198 DECL(ALC_INVALID_ENUM),
199 DECL(ALC_INVALID_VALUE),
200 DECL(ALC_OUT_OF_MEMORY),
202 DECL(AL_INVALID),
203 DECL(AL_NONE),
204 DECL(AL_FALSE),
205 DECL(AL_TRUE),
207 DECL(AL_SOURCE_RELATIVE),
208 DECL(AL_CONE_INNER_ANGLE),
209 DECL(AL_CONE_OUTER_ANGLE),
210 DECL(AL_PITCH),
211 DECL(AL_POSITION),
212 DECL(AL_DIRECTION),
213 DECL(AL_VELOCITY),
214 DECL(AL_LOOPING),
215 DECL(AL_BUFFER),
216 DECL(AL_GAIN),
217 DECL(AL_MIN_GAIN),
218 DECL(AL_MAX_GAIN),
219 DECL(AL_ORIENTATION),
220 DECL(AL_REFERENCE_DISTANCE),
221 DECL(AL_ROLLOFF_FACTOR),
222 DECL(AL_CONE_OUTER_GAIN),
223 DECL(AL_MAX_DISTANCE),
224 DECL(AL_SEC_OFFSET),
225 DECL(AL_SAMPLE_OFFSET),
226 DECL(AL_BYTE_OFFSET),
227 DECL(AL_SOURCE_TYPE),
228 DECL(AL_STATIC),
229 DECL(AL_STREAMING),
230 DECL(AL_UNDETERMINED),
232 DECL(AL_SOURCE_STATE),
233 DECL(AL_INITIAL),
234 DECL(AL_PLAYING),
235 DECL(AL_PAUSED),
236 DECL(AL_STOPPED),
238 DECL(AL_BUFFERS_QUEUED),
239 DECL(AL_BUFFERS_PROCESSED),
241 DECL(AL_FORMAT_MONO8),
242 DECL(AL_FORMAT_MONO16),
243 DECL(AL_FORMAT_STEREO8),
244 DECL(AL_FORMAT_STEREO16),
246 DECL(AL_FREQUENCY),
247 DECL(AL_BITS),
248 DECL(AL_CHANNELS),
249 DECL(AL_SIZE),
251 DECL(AL_UNUSED),
252 DECL(AL_PENDING),
253 DECL(AL_PROCESSED),
255 DECL(AL_NO_ERROR),
256 DECL(AL_INVALID_NAME),
257 DECL(AL_INVALID_ENUM),
258 DECL(AL_INVALID_VALUE),
259 DECL(AL_INVALID_OPERATION),
260 DECL(AL_OUT_OF_MEMORY),
262 DECL(AL_VENDOR),
263 DECL(AL_VERSION),
264 DECL(AL_RENDERER),
265 DECL(AL_EXTENSIONS),
267 DECL(AL_DOPPLER_FACTOR),
268 DECL(AL_DOPPLER_VELOCITY),
269 DECL(AL_DISTANCE_MODEL),
270 DECL(AL_SPEED_OF_SOUND),
272 DECL(AL_INVERSE_DISTANCE),
273 DECL(AL_INVERSE_DISTANCE_CLAMPED),
274 DECL(AL_LINEAR_DISTANCE),
275 DECL(AL_LINEAR_DISTANCE_CLAMPED),
276 DECL(AL_EXPONENT_DISTANCE),
277 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
279 #undef DECL
281 [[nodiscard]] constexpr auto GetNoErrorString() noexcept { return "No Error"; }
282 [[nodiscard]] constexpr auto GetInvalidDeviceString() noexcept { return "Invalid Device"; }
283 [[nodiscard]] constexpr auto GetInvalidContextString() noexcept { return "Invalid Context"; }
284 [[nodiscard]] constexpr auto GetInvalidEnumString() noexcept { return "Invalid Enum"; }
285 [[nodiscard]] constexpr auto GetInvalidValueString() noexcept { return "Invalid Value"; }
286 [[nodiscard]] constexpr auto GetOutOfMemoryString() noexcept { return "Out of Memory"; }
288 [[nodiscard]] constexpr auto GetExtensionList() noexcept -> std::string_view
290 return "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
291 "ALC_EXT_thread_local_context"sv;
294 constexpr ALCint alcMajorVersion = 1;
295 constexpr ALCint alcMinorVersion = 1;
298 std::recursive_mutex EnumerationLock;
299 std::mutex ContextSwitchLock;
301 std::atomic<ALCenum> LastError{ALC_NO_ERROR};
302 std::unordered_map<ALCdevice*,ALCuint> DeviceIfaceMap;
303 std::unordered_map<ALCcontext*,ALCuint> ContextIfaceMap;
305 template<typename T, typename U, typename V>
306 auto maybe_get(std::unordered_map<T,U> &list, V&& key) -> std::optional<U>
308 auto iter = list.find(std::forward<V>(key));
309 if(iter != list.end()) return iter->second;
310 return std::nullopt;
314 struct EnumeratedList {
315 std::vector<ALCchar> Names;
316 std::vector<ALCuint> Indicies;
318 void clear()
320 Names.clear();
321 Indicies.clear();
324 void AppendDeviceList(const ALCchar *names, ALCuint idx);
325 [[nodiscard]]
326 auto GetDriverIndexForName(const std::string_view name) const -> std::optional<ALCuint>;
328 EnumeratedList DevicesList;
329 EnumeratedList AllDevicesList;
330 EnumeratedList CaptureDevicesList;
332 void EnumeratedList::AppendDeviceList(const ALCchar* names, ALCuint idx)
334 const ALCchar *name_end = names;
335 if(!name_end) return;
337 size_t count{0};
338 while(*name_end)
340 TRACE("Enumerated \"%s\", driver %u\n", name_end, idx);
341 ++count;
342 name_end += strlen(name_end)+1; /* NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) */
344 if(names == name_end)
345 return;
347 Names.reserve(Names.size() + static_cast<size_t>(name_end - names) + 1);
348 Names.insert(Names.cend(), names, name_end);
350 Indicies.reserve(Indicies.size() + count);
351 Indicies.insert(Indicies.cend(), count, idx);
354 auto EnumeratedList::GetDriverIndexForName(const std::string_view name) const -> std::optional<ALCuint>
356 auto devnames = Names.cbegin();
357 auto index = Indicies.cbegin();
359 while(devnames != Names.cend() && *devnames)
361 const auto devname = std::string_view{al::to_address(devnames)};
362 if(name == devname) return *index;
364 devnames += ptrdiff_t(devname.size()+1);
365 ++index;
367 return std::nullopt;
371 void InitCtxFuncs(DriverIface &iface)
373 ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())};
375 #define LOAD_PROC(x) do { \
376 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
377 if(!iface.x) \
378 ERR("Failed to find entry point for %s in %ls\n", #x, \
379 iface.Name.c_str()); \
380 } while(0)
381 if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX"))
383 LOAD_PROC(alGenFilters);
384 LOAD_PROC(alDeleteFilters);
385 LOAD_PROC(alIsFilter);
386 LOAD_PROC(alFilterf);
387 LOAD_PROC(alFilterfv);
388 LOAD_PROC(alFilteri);
389 LOAD_PROC(alFilteriv);
390 LOAD_PROC(alGetFilterf);
391 LOAD_PROC(alGetFilterfv);
392 LOAD_PROC(alGetFilteri);
393 LOAD_PROC(alGetFilteriv);
394 LOAD_PROC(alGenEffects);
395 LOAD_PROC(alDeleteEffects);
396 LOAD_PROC(alIsEffect);
397 LOAD_PROC(alEffectf);
398 LOAD_PROC(alEffectfv);
399 LOAD_PROC(alEffecti);
400 LOAD_PROC(alEffectiv);
401 LOAD_PROC(alGetEffectf);
402 LOAD_PROC(alGetEffectfv);
403 LOAD_PROC(alGetEffecti);
404 LOAD_PROC(alGetEffectiv);
405 LOAD_PROC(alGenAuxiliaryEffectSlots);
406 LOAD_PROC(alDeleteAuxiliaryEffectSlots);
407 LOAD_PROC(alIsAuxiliaryEffectSlot);
408 LOAD_PROC(alAuxiliaryEffectSlotf);
409 LOAD_PROC(alAuxiliaryEffectSlotfv);
410 LOAD_PROC(alAuxiliaryEffectSloti);
411 LOAD_PROC(alAuxiliaryEffectSlotiv);
412 LOAD_PROC(alGetAuxiliaryEffectSlotf);
413 LOAD_PROC(alGetAuxiliaryEffectSlotfv);
414 LOAD_PROC(alGetAuxiliaryEffectSloti);
415 LOAD_PROC(alGetAuxiliaryEffectSlotiv);
417 #undef LOAD_PROC
420 } /* namespace */
423 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) noexcept
425 ALCdevice *device{nullptr};
426 std::optional<ALCuint> idx;
428 /* Prior to the enumeration extension, apps would hardcode these names as a
429 * quality hint for the wrapper driver. Ignore them since there's no sane
430 * way to map them.
432 if(devicename && *devicename != '\0' && devicename != "DirectSound3D"sv
433 && devicename != "DirectSound"sv && devicename != "MMSYSTEM"sv)
436 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
437 if(DevicesList.Names.empty())
438 std::ignore = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
439 idx = DevicesList.GetDriverIndexForName(devicename);
440 if(!idx)
442 if(AllDevicesList.Names.empty())
443 std::ignore = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
444 idx = AllDevicesList.GetDriverIndexForName(devicename);
448 if(!idx)
450 LastError.store(ALC_INVALID_VALUE);
451 TRACE("Failed to find driver for name \"%s\"\n", devicename);
452 return nullptr;
454 TRACE("Found driver %u for name \"%s\"\n", *idx, devicename);
455 device = DriverList[*idx]->alcOpenDevice(devicename);
457 else
459 ALCuint drvidx{0};
460 for(const auto &drv : DriverList)
462 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
463 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
465 TRACE("Using default device from driver %u\n", drvidx);
466 device = drv->alcOpenDevice(nullptr);
467 idx = drvidx;
468 break;
470 ++drvidx;
474 if(device)
476 try {
477 DeviceIfaceMap.emplace(device, idx.value());
479 catch(...) {
480 DriverList[idx.value()]->alcCloseDevice(device);
481 device = nullptr;
485 return device;
488 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept
490 if(const auto idx = maybe_get(DeviceIfaceMap, device))
492 if(!DriverList[*idx]->alcCloseDevice(device))
493 return ALC_FALSE;
494 DeviceIfaceMap.erase(device);
495 return ALC_TRUE;
498 LastError.store(ALC_INVALID_DEVICE);
499 return ALC_FALSE;
503 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) noexcept
505 const auto idx = maybe_get(DeviceIfaceMap, device);
506 if(!idx)
508 LastError.store(ALC_INVALID_DEVICE);
509 return nullptr;
512 ALCcontext *context{DriverList[*idx]->alcCreateContext(device, attrlist)};
513 if(context)
515 try {
516 ContextIfaceMap.emplace(context, *idx);
518 catch(...) {
519 DriverList[*idx]->alcDestroyContext(context);
520 context = nullptr;
524 return context;
527 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexcept
529 std::lock_guard<std::mutex> ctxlock{ContextSwitchLock};
531 std::optional<ALCuint> idx;
532 if(context)
534 idx = maybe_get(ContextIfaceMap, context);
535 if(!idx)
537 LastError.store(ALC_INVALID_CONTEXT);
538 return ALC_FALSE;
540 if(!DriverList[*idx]->alcMakeContextCurrent(context))
541 return ALC_FALSE;
543 std::call_once(DriverList[*idx]->InitOnceCtx, [idx]{ InitCtxFuncs(*DriverList[*idx]); });
546 /* Unset the context from the old driver if it's different from the new
547 * current one.
549 if(!idx)
551 DriverIface *oldiface{GetThreadDriver()};
552 if(oldiface) oldiface->alcSetThreadContext(nullptr);
553 oldiface = CurrentCtxDriver.exchange(nullptr);
554 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
556 else
558 DriverIface *oldiface{GetThreadDriver()};
559 if(oldiface && oldiface != DriverList[*idx].get())
560 oldiface->alcSetThreadContext(nullptr);
561 oldiface = CurrentCtxDriver.exchange(DriverList[*idx].get());
562 if(oldiface && oldiface != DriverList[*idx].get())
563 oldiface->alcMakeContextCurrent(nullptr);
565 SetThreadDriver(nullptr);
567 return ALC_TRUE;
570 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) noexcept
572 if(const auto idx = maybe_get(ContextIfaceMap, context))
573 return DriverList[*idx]->alcProcessContext(context);
575 LastError.store(ALC_INVALID_CONTEXT);
578 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) noexcept
580 if(const auto idx = maybe_get(ContextIfaceMap, context))
581 return DriverList[*idx]->alcSuspendContext(context);
583 LastError.store(ALC_INVALID_CONTEXT);
586 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept
588 if(const auto idx = maybe_get(ContextIfaceMap, context))
590 DriverList[*idx]->alcDestroyContext(context);
591 ContextIfaceMap.erase(context);
592 return;
594 LastError.store(ALC_INVALID_CONTEXT);
597 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext() noexcept
599 DriverIface *iface{GetThreadDriver()};
600 if(!iface) iface = CurrentCtxDriver.load();
601 return iface ? iface->alcGetCurrentContext() : nullptr;
604 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) noexcept
606 if(const auto idx = maybe_get(ContextIfaceMap, context))
607 return DriverList[*idx]->alcGetContextsDevice(context);
609 LastError.store(ALC_INVALID_CONTEXT);
610 return nullptr;
614 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) noexcept
616 if(device)
618 if(const auto idx = maybe_get(DeviceIfaceMap, device))
619 return DriverList[*idx]->alcGetError(device);
620 return ALC_INVALID_DEVICE;
622 return LastError.exchange(ALC_NO_ERROR);
625 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) noexcept
627 if(device)
629 if(const auto idx = maybe_get(DeviceIfaceMap, device))
630 return DriverList[*idx]->alcIsExtensionPresent(device, extname);
632 LastError.store(ALC_INVALID_DEVICE);
633 return ALC_FALSE;
636 const auto tofind = std::string_view{extname};
637 const auto extlist = GetExtensionList();
638 auto matchpos = extlist.find(tofind);
639 while(matchpos != std::string_view::npos)
641 const auto endpos = matchpos + tofind.size();
642 if((matchpos == 0 || std::isspace(extlist[matchpos-1]))
643 && (endpos == extlist.size() || std::isspace(extlist[endpos])))
644 return ALC_TRUE;
645 matchpos = extlist.find(tofind, matchpos+1);
647 return ALC_FALSE;
650 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) noexcept
652 if(device)
654 if(const auto idx = maybe_get(DeviceIfaceMap, device))
655 return DriverList[*idx]->alcGetProcAddress(device, funcname);
657 LastError.store(ALC_INVALID_DEVICE);
658 return nullptr;
661 auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
662 [funcname](const FuncExportEntry &entry) -> bool
663 { return strcmp(funcname, entry.funcName) == 0; }
665 return (iter != alcFunctions.cend()) ? iter->address : nullptr;
668 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) noexcept
670 if(device)
672 if(const auto idx = maybe_get(DeviceIfaceMap, device))
673 return DriverList[*idx]->alcGetEnumValue(device, enumname);
675 LastError.store(ALC_INVALID_DEVICE);
676 return 0;
679 auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
680 [enumname](const EnumExportEntry &entry) -> bool
681 { return strcmp(enumname, entry.enumName) == 0; }
683 return (iter != alcEnumerations.cend()) ? iter->value : 0;
686 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) noexcept
688 if(device)
690 if(const auto idx = maybe_get(DeviceIfaceMap, device))
691 return DriverList[*idx]->alcGetString(device, param);
693 LastError.store(ALC_INVALID_DEVICE);
694 return nullptr;
697 switch(param)
699 case ALC_NO_ERROR: return GetNoErrorString();
700 case ALC_INVALID_ENUM: return GetInvalidEnumString();
701 case ALC_INVALID_VALUE: return GetInvalidValueString();
702 case ALC_INVALID_DEVICE: return GetInvalidDeviceString();
703 case ALC_INVALID_CONTEXT: return GetInvalidContextString();
704 case ALC_OUT_OF_MEMORY: return GetOutOfMemoryString();
705 case ALC_EXTENSIONS: return GetExtensionList().data();
707 case ALC_DEVICE_SPECIFIER:
709 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
710 DevicesList.clear();
711 ALCuint idx{0};
712 for(const auto &drv : DriverList)
714 /* Only enumerate names from drivers that support it. */
715 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
716 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
717 DevicesList.AppendDeviceList(drv->alcGetString(nullptr,ALC_DEVICE_SPECIFIER), idx);
718 ++idx;
720 /* Ensure the list is double-null termianted. */
721 if(DevicesList.Names.empty())
722 DevicesList.Names.emplace_back('\0');
723 DevicesList.Names.emplace_back('\0');
724 return DevicesList.Names.data();
727 case ALC_ALL_DEVICES_SPECIFIER:
729 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
730 AllDevicesList.clear();
731 ALCuint idx{0};
732 for(const auto &drv : DriverList)
734 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
735 * standard enumeration.
737 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
738 AllDevicesList.AppendDeviceList(
739 drv->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx);
740 else if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
741 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
742 AllDevicesList.AppendDeviceList(
743 drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
744 ++idx;
746 /* Ensure the list is double-null termianted. */
747 if(AllDevicesList.Names.empty())
748 AllDevicesList.Names.emplace_back('\0');
749 AllDevicesList.Names.emplace_back('\0');
750 return AllDevicesList.Names.data();
753 case ALC_CAPTURE_DEVICE_SPECIFIER:
755 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
756 CaptureDevicesList.clear();
757 ALCuint idx{0};
758 for(const auto &drv : DriverList)
760 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
761 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
762 CaptureDevicesList.AppendDeviceList(
763 drv->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx);
764 ++idx;
766 /* Ensure the list is double-null termianted. */
767 if(CaptureDevicesList.Names.empty())
768 CaptureDevicesList.Names.emplace_back('\0');
769 CaptureDevicesList.Names.emplace_back('\0');
770 return CaptureDevicesList.Names.data();
773 case ALC_DEFAULT_DEVICE_SPECIFIER:
775 for(const auto &drv : DriverList)
777 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
778 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
779 return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
781 return "";
784 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
786 for(const auto &drv : DriverList)
788 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE)
789 return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
791 return "";
794 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
796 for(const auto &drv : DriverList)
798 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
799 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
800 return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
802 return "";
805 default:
806 LastError.store(ALC_INVALID_ENUM);
807 break;
809 return nullptr;
812 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) noexcept
814 if(device)
816 if(const auto idx = maybe_get(DeviceIfaceMap, device))
817 return DriverList[*idx]->alcGetIntegerv(device, param, size, values);
819 LastError.store(ALC_INVALID_DEVICE);
820 return;
823 if(size <= 0 || values == nullptr)
825 LastError.store(ALC_INVALID_VALUE);
826 return;
829 switch(param)
831 case ALC_MAJOR_VERSION:
832 if(size >= 1)
834 *values = alcMajorVersion;
835 return;
837 LastError.store(ALC_INVALID_VALUE);
838 return;
839 case ALC_MINOR_VERSION:
840 if(size >= 1)
842 *values = alcMinorVersion;
843 return;
845 LastError.store(ALC_INVALID_VALUE);
846 return;
848 case ALC_ATTRIBUTES_SIZE:
849 case ALC_ALL_ATTRIBUTES:
850 case ALC_FREQUENCY:
851 case ALC_REFRESH:
852 case ALC_SYNC:
853 case ALC_MONO_SOURCES:
854 case ALC_STEREO_SOURCES:
855 case ALC_CAPTURE_SAMPLES:
856 LastError.store(ALC_INVALID_DEVICE);
857 return;
859 default:
860 LastError.store(ALC_INVALID_ENUM);
861 return;
866 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency,
867 ALCenum format, ALCsizei buffersize) noexcept
869 ALCdevice *device{nullptr};
870 std::optional<ALCuint> idx;
872 if(devicename && *devicename != '\0')
875 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
876 if(CaptureDevicesList.Names.empty())
877 std::ignore = alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER);
878 idx = CaptureDevicesList.GetDriverIndexForName(devicename);
881 if(!idx)
883 LastError.store(ALC_INVALID_VALUE);
884 TRACE("Failed to find driver for name \"%s\"\n", devicename);
885 return nullptr;
887 TRACE("Found driver %u for name \"%s\"\n", *idx, devicename);
888 device = DriverList[*idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize);
890 else
892 ALCuint drvidx{0};
893 for(const auto &drv : DriverList)
895 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
896 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
898 TRACE("Using default capture device from driver %u\n", drvidx);
899 device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
900 idx = drvidx;
901 break;
903 ++drvidx;
907 if(device)
909 try {
910 DeviceIfaceMap.emplace(device, idx.value());
912 catch(...) {
913 DriverList[idx.value()]->alcCaptureCloseDevice(device);
914 device = nullptr;
918 return device;
921 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) noexcept
923 if(const auto idx = maybe_get(DeviceIfaceMap, device))
925 if(!DriverList[*idx]->alcCaptureCloseDevice(device))
926 return ALC_FALSE;
927 DeviceIfaceMap.erase(device);
928 return ALC_TRUE;
931 LastError.store(ALC_INVALID_DEVICE);
932 return ALC_FALSE;
935 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) noexcept
937 if(const auto idx = maybe_get(DeviceIfaceMap, device))
938 return DriverList[*idx]->alcCaptureStart(device);
939 LastError.store(ALC_INVALID_DEVICE);
942 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) noexcept
944 if(const auto idx = maybe_get(DeviceIfaceMap, device))
945 return DriverList[*idx]->alcCaptureStop(device);
946 LastError.store(ALC_INVALID_DEVICE);
949 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) noexcept
951 if(const auto idx = maybe_get(DeviceIfaceMap, device))
952 return DriverList[*idx]->alcCaptureSamples(device, buffer, samples);
953 LastError.store(ALC_INVALID_DEVICE);
957 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) noexcept
959 if(!context)
961 DriverIface *oldiface{GetThreadDriver()};
962 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
963 return ALC_FALSE;
964 SetThreadDriver(nullptr);
965 return ALC_TRUE;
968 ALCenum err{ALC_INVALID_CONTEXT};
969 if(const auto idx = maybe_get(ContextIfaceMap, context))
971 if(DriverList[*idx]->alcSetThreadContext(context))
973 std::call_once(DriverList[*idx]->InitOnceCtx, [idx]{InitCtxFuncs(*DriverList[*idx]);});
975 DriverIface *oldiface{GetThreadDriver()};
976 if(oldiface != DriverList[*idx].get())
978 SetThreadDriver(DriverList[*idx].get());
979 if(oldiface) oldiface->alcSetThreadContext(nullptr);
981 return ALC_TRUE;
983 err = DriverList[*idx]->alcGetError(nullptr);
985 LastError.store(err);
986 return ALC_FALSE;
989 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext() noexcept
991 if(DriverIface *iface{GetThreadDriver()})
992 return iface->alcGetThreadContext();
993 return nullptr;