Clean up some clang-tidy warnings in the router
[openal-soft.git] / router / alc.cpp
blob7e40f4d2d3d18098976fd2a8a012e8eb9ef4e0eb
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*,ALint> DeviceIfaceMap;
303 std::unordered_map<ALCcontext*,ALint> ContextIfaceMap;
305 template<typename T, typename U, typename V>
306 std::optional<U> maybe_get(std::unordered_map<T,U> &list, V&& key)
308 auto iter = list.find(std::forward<V>(key));
309 if(iter == list.end()) return std::nullopt;
310 return iter->second;
314 struct EnumeratedList {
315 std::vector<ALCchar> Names;
316 std::vector<ALCint> Indicies;
318 void clear()
320 Names.clear();
321 Indicies.clear();
324 void AppendDeviceList(const ALCchar *names, ALint idx);
325 [[nodiscard]]
326 auto GetDriverIndexForName(const std::string_view name) const -> ALint;
328 EnumeratedList DevicesList;
329 EnumeratedList AllDevicesList;
330 EnumeratedList CaptureDevicesList;
332 void EnumeratedList::AppendDeviceList(const ALCchar* names, ALint 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 %d\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 -> ALint
356 auto devnames = Names.cbegin();
357 auto index = Indicies.cbegin();
359 while(devnames != Names.cend() && *devnames)
361 if(name == al::to_address(devnames))
362 return *index;
363 devnames += ptrdiff_t(strlen(al::to_address(devnames))+1);
364 ++index;
366 return -1;
370 void InitCtxFuncs(DriverIface &iface)
372 ALCdevice *device{iface.alcGetContextsDevice(iface.alcGetCurrentContext())};
374 #define LOAD_PROC(x) do { \
375 iface.x = reinterpret_cast<decltype(iface.x)>(iface.alGetProcAddress(#x));\
376 if(!iface.x) \
377 ERR("Failed to find entry point for %s in %ls\n", #x, \
378 iface.Name.c_str()); \
379 } while(0)
380 if(iface.alcIsExtensionPresent(device, "ALC_EXT_EFX"))
382 LOAD_PROC(alGenFilters);
383 LOAD_PROC(alDeleteFilters);
384 LOAD_PROC(alIsFilter);
385 LOAD_PROC(alFilterf);
386 LOAD_PROC(alFilterfv);
387 LOAD_PROC(alFilteri);
388 LOAD_PROC(alFilteriv);
389 LOAD_PROC(alGetFilterf);
390 LOAD_PROC(alGetFilterfv);
391 LOAD_PROC(alGetFilteri);
392 LOAD_PROC(alGetFilteriv);
393 LOAD_PROC(alGenEffects);
394 LOAD_PROC(alDeleteEffects);
395 LOAD_PROC(alIsEffect);
396 LOAD_PROC(alEffectf);
397 LOAD_PROC(alEffectfv);
398 LOAD_PROC(alEffecti);
399 LOAD_PROC(alEffectiv);
400 LOAD_PROC(alGetEffectf);
401 LOAD_PROC(alGetEffectfv);
402 LOAD_PROC(alGetEffecti);
403 LOAD_PROC(alGetEffectiv);
404 LOAD_PROC(alGenAuxiliaryEffectSlots);
405 LOAD_PROC(alDeleteAuxiliaryEffectSlots);
406 LOAD_PROC(alIsAuxiliaryEffectSlot);
407 LOAD_PROC(alAuxiliaryEffectSlotf);
408 LOAD_PROC(alAuxiliaryEffectSlotfv);
409 LOAD_PROC(alAuxiliaryEffectSloti);
410 LOAD_PROC(alAuxiliaryEffectSlotiv);
411 LOAD_PROC(alGetAuxiliaryEffectSlotf);
412 LOAD_PROC(alGetAuxiliaryEffectSlotfv);
413 LOAD_PROC(alGetAuxiliaryEffectSloti);
414 LOAD_PROC(alGetAuxiliaryEffectSlotiv);
416 #undef LOAD_PROC
419 } /* namespace */
422 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) noexcept
424 ALCdevice *device{nullptr};
425 ALint idx{0};
427 /* Prior to the enumeration extension, apps would hardcode these names as a
428 * quality hint for the wrapper driver. Ignore them since there's no sane
429 * way to map them.
431 if(devicename && (*devicename == '\0' || devicename == "DirectSound3D"sv
432 || devicename == "DirectSound"sv || devicename == "MMSYSTEM"sv))
433 devicename = nullptr;
434 if(devicename)
437 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
438 if(DevicesList.Names.empty())
439 std::ignore = alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
440 idx = DevicesList.GetDriverIndexForName(devicename);
441 if(idx < 0)
443 if(AllDevicesList.Names.empty())
444 std::ignore = alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
445 idx = AllDevicesList.GetDriverIndexForName(devicename);
449 if(idx < 0)
451 LastError.store(ALC_INVALID_VALUE);
452 TRACE("Failed to find driver for name \"%s\"\n", devicename);
453 return nullptr;
455 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
456 device = DriverList[idx]->alcOpenDevice(devicename);
458 else
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 %d\n", idx);
466 device = drv->alcOpenDevice(nullptr);
467 break;
469 ++idx;
473 if(device)
475 try {
476 DeviceIfaceMap.emplace(device, idx);
478 catch(...) {
479 DriverList[idx]->alcCloseDevice(device);
480 device = nullptr;
484 return device;
487 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) noexcept
489 if(const auto idx = maybe_get(DeviceIfaceMap, device))
491 if(!DriverList[*idx]->alcCloseDevice(device))
492 return ALC_FALSE;
493 DeviceIfaceMap.erase(device);
494 return ALC_TRUE;
497 LastError.store(ALC_INVALID_DEVICE);
498 return ALC_FALSE;
502 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) noexcept
504 const auto idx = maybe_get(DeviceIfaceMap, device);
505 if(!idx)
507 LastError.store(ALC_INVALID_DEVICE);
508 return nullptr;
511 ALCcontext *context{DriverList[*idx]->alcCreateContext(device, attrlist)};
512 if(context)
514 try {
515 ContextIfaceMap.emplace(context, *idx);
517 catch(...) {
518 DriverList[*idx]->alcDestroyContext(context);
519 context = nullptr;
523 return context;
526 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) noexcept
528 std::lock_guard<std::mutex> ctxlock{ContextSwitchLock};
530 std::optional<ALint> idx;
531 if(context)
533 idx = maybe_get(ContextIfaceMap, context);
534 if(!idx)
536 LastError.store(ALC_INVALID_CONTEXT);
537 return ALC_FALSE;
539 if(!DriverList[*idx]->alcMakeContextCurrent(context))
540 return ALC_FALSE;
542 std::call_once(DriverList[*idx]->InitOnceCtx, [idx]{ InitCtxFuncs(*DriverList[*idx]); });
545 /* Unset the context from the old driver if it's different from the new
546 * current one.
548 if(!idx)
550 DriverIface *oldiface{GetThreadDriver()};
551 if(oldiface) oldiface->alcSetThreadContext(nullptr);
552 oldiface = CurrentCtxDriver.exchange(nullptr);
553 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
555 else
557 DriverIface *oldiface{GetThreadDriver()};
558 if(oldiface && oldiface != DriverList[*idx].get())
559 oldiface->alcSetThreadContext(nullptr);
560 oldiface = CurrentCtxDriver.exchange(DriverList[*idx].get());
561 if(oldiface && oldiface != DriverList[*idx].get())
562 oldiface->alcMakeContextCurrent(nullptr);
564 SetThreadDriver(nullptr);
566 return ALC_TRUE;
569 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) noexcept
571 if(const auto idx = maybe_get(ContextIfaceMap, context))
572 return DriverList[*idx]->alcProcessContext(context);
574 LastError.store(ALC_INVALID_CONTEXT);
577 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) noexcept
579 if(const auto idx = maybe_get(ContextIfaceMap, context))
580 return DriverList[*idx]->alcSuspendContext(context);
582 LastError.store(ALC_INVALID_CONTEXT);
585 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) noexcept
587 if(const auto idx = maybe_get(ContextIfaceMap, context))
589 DriverList[*idx]->alcDestroyContext(context);
590 ContextIfaceMap.erase(context);
591 return;
593 LastError.store(ALC_INVALID_CONTEXT);
596 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext() noexcept
598 DriverIface *iface{GetThreadDriver()};
599 if(!iface) iface = CurrentCtxDriver.load();
600 return iface ? iface->alcGetCurrentContext() : nullptr;
603 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) noexcept
605 if(const auto idx = maybe_get(ContextIfaceMap, context))
606 return DriverList[*idx]->alcGetContextsDevice(context);
608 LastError.store(ALC_INVALID_CONTEXT);
609 return nullptr;
613 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) noexcept
615 if(device)
617 if(const auto idx = maybe_get(DeviceIfaceMap, device))
618 return DriverList[*idx]->alcGetError(device);
619 return ALC_INVALID_DEVICE;
621 return LastError.exchange(ALC_NO_ERROR);
624 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) noexcept
626 if(device)
628 if(const auto idx = maybe_get(DeviceIfaceMap, device))
629 return DriverList[*idx]->alcIsExtensionPresent(device, extname);
631 LastError.store(ALC_INVALID_DEVICE);
632 return ALC_FALSE;
635 const auto tofind = std::string_view{extname};
636 const auto extlist = GetExtensionList();
637 auto matchpos = extlist.find(tofind);
638 while(matchpos != std::string_view::npos)
640 const auto endpos = matchpos + tofind.size();
641 if((matchpos == 0 || std::isspace(extlist[matchpos-1]))
642 && (endpos == extlist.size() || std::isspace(extlist[endpos])))
643 return ALC_TRUE;
644 matchpos = extlist.find(tofind, matchpos+1);
646 return ALC_FALSE;
649 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) noexcept
651 if(device)
653 if(const auto idx = maybe_get(DeviceIfaceMap, device))
654 return DriverList[*idx]->alcGetProcAddress(device, funcname);
656 LastError.store(ALC_INVALID_DEVICE);
657 return nullptr;
660 auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
661 [funcname](const FuncExportEntry &entry) -> bool
662 { return strcmp(funcname, entry.funcName) == 0; }
664 return (iter != alcFunctions.cend()) ? iter->address : nullptr;
667 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) noexcept
669 if(device)
671 if(const auto idx = maybe_get(DeviceIfaceMap, device))
672 return DriverList[*idx]->alcGetEnumValue(device, enumname);
674 LastError.store(ALC_INVALID_DEVICE);
675 return 0;
678 auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
679 [enumname](const EnumExportEntry &entry) -> bool
680 { return strcmp(enumname, entry.enumName) == 0; }
682 return (iter != alcEnumerations.cend()) ? iter->value : 0;
685 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) noexcept
687 if(device)
689 if(const auto idx = maybe_get(DeviceIfaceMap, device))
690 return DriverList[*idx]->alcGetString(device, param);
692 LastError.store(ALC_INVALID_DEVICE);
693 return nullptr;
696 switch(param)
698 case ALC_NO_ERROR: return GetNoErrorString();
699 case ALC_INVALID_ENUM: return GetInvalidEnumString();
700 case ALC_INVALID_VALUE: return GetInvalidValueString();
701 case ALC_INVALID_DEVICE: return GetInvalidDeviceString();
702 case ALC_INVALID_CONTEXT: return GetInvalidContextString();
703 case ALC_OUT_OF_MEMORY: return GetOutOfMemoryString();
704 case ALC_EXTENSIONS: return GetExtensionList().data();
706 case ALC_DEVICE_SPECIFIER:
708 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
709 DevicesList.clear();
710 ALint idx{0};
711 for(const auto &drv : DriverList)
713 /* Only enumerate names from drivers that support it. */
714 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
715 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
716 DevicesList.AppendDeviceList(drv->alcGetString(nullptr,ALC_DEVICE_SPECIFIER), idx);
717 ++idx;
719 /* Ensure the list is double-null termianted. */
720 if(DevicesList.Names.empty())
721 DevicesList.Names.emplace_back('\0');
722 DevicesList.Names.emplace_back('\0');
723 return DevicesList.Names.data();
726 case ALC_ALL_DEVICES_SPECIFIER:
728 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
729 AllDevicesList.clear();
730 ALint idx{0};
731 for(const auto &drv : DriverList)
733 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
734 * standard enumeration.
736 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
737 AllDevicesList.AppendDeviceList(
738 drv->alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx);
739 else if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
740 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
741 AllDevicesList.AppendDeviceList(
742 drv->alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx);
743 ++idx;
745 /* Ensure the list is double-null termianted. */
746 if(AllDevicesList.Names.empty())
747 AllDevicesList.Names.emplace_back('\0');
748 AllDevicesList.Names.emplace_back('\0');
749 return AllDevicesList.Names.data();
752 case ALC_CAPTURE_DEVICE_SPECIFIER:
754 std::lock_guard<std::recursive_mutex> enumlock{EnumerationLock};
755 CaptureDevicesList.clear();
756 ALint idx{0};
757 for(const auto &drv : DriverList)
759 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
760 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
761 CaptureDevicesList.AppendDeviceList(
762 drv->alcGetString(nullptr, ALC_CAPTURE_DEVICE_SPECIFIER), idx);
763 ++idx;
765 /* Ensure the list is double-null termianted. */
766 if(CaptureDevicesList.Names.empty())
767 CaptureDevicesList.Names.emplace_back('\0');
768 CaptureDevicesList.Names.emplace_back('\0');
769 return CaptureDevicesList.Names.data();
772 case ALC_DEFAULT_DEVICE_SPECIFIER:
774 for(const auto &drv : DriverList)
776 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
777 || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
778 return drv->alcGetString(nullptr, ALC_DEFAULT_DEVICE_SPECIFIER);
780 return "";
783 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
785 for(const auto &drv : DriverList)
787 if(drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT") != ALC_FALSE)
788 return drv->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
790 return "";
793 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
795 for(const auto &drv : DriverList)
797 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
798 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
799 return drv->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
801 return "";
804 default:
805 LastError.store(ALC_INVALID_ENUM);
806 break;
808 return nullptr;
811 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) noexcept
813 if(device)
815 if(const auto idx = maybe_get(DeviceIfaceMap, device))
816 return DriverList[*idx]->alcGetIntegerv(device, param, size, values);
818 LastError.store(ALC_INVALID_DEVICE);
819 return;
822 if(size <= 0 || values == nullptr)
824 LastError.store(ALC_INVALID_VALUE);
825 return;
828 switch(param)
830 case ALC_MAJOR_VERSION:
831 if(size >= 1)
833 *values = alcMajorVersion;
834 return;
836 /*fall-through*/
837 case ALC_MINOR_VERSION:
838 if(size >= 1)
840 *values = alcMinorVersion;
841 return;
843 LastError.store(ALC_INVALID_VALUE);
844 return;
846 case ALC_ATTRIBUTES_SIZE:
847 case ALC_ALL_ATTRIBUTES:
848 case ALC_FREQUENCY:
849 case ALC_REFRESH:
850 case ALC_SYNC:
851 case ALC_MONO_SOURCES:
852 case ALC_STEREO_SOURCES:
853 case ALC_CAPTURE_SAMPLES:
854 LastError.store(ALC_INVALID_DEVICE);
855 return;
857 default:
858 LastError.store(ALC_INVALID_ENUM);
859 return;
864 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency,
865 ALCenum format, ALCsizei buffersize) noexcept
867 ALCdevice *device{nullptr};
868 ALint idx{0};
870 if(devicename && *devicename == '\0')
871 devicename = nullptr;
872 if(devicename)
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 < 0)
883 LastError.store(ALC_INVALID_VALUE);
884 TRACE("Failed to find driver for name \"%s\"\n", devicename);
885 return nullptr;
887 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
888 device = DriverList[idx]->alcCaptureOpenDevice(devicename, frequency, format, buffersize);
890 else
892 for(const auto &drv : DriverList)
894 if(drv->ALCVer >= MAKE_ALC_VER(1, 1)
895 || drv->alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
897 TRACE("Using default capture device from driver %d\n", idx);
898 device = drv->alcCaptureOpenDevice(nullptr, frequency, format, buffersize);
899 break;
901 ++idx;
905 if(device)
907 try {
908 DeviceIfaceMap.emplace(device, idx);
910 catch(...) {
911 DriverList[idx]->alcCaptureCloseDevice(device);
912 device = nullptr;
916 return device;
919 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) noexcept
921 if(const auto idx = maybe_get(DeviceIfaceMap, device))
923 if(!DriverList[*idx]->alcCaptureCloseDevice(device))
924 return ALC_FALSE;
925 DeviceIfaceMap.erase(device);
926 return ALC_TRUE;
929 LastError.store(ALC_INVALID_DEVICE);
930 return ALC_FALSE;
933 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) noexcept
935 if(const auto idx = maybe_get(DeviceIfaceMap, device))
936 return DriverList[*idx]->alcCaptureStart(device);
937 LastError.store(ALC_INVALID_DEVICE);
940 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) noexcept
942 if(const auto idx = maybe_get(DeviceIfaceMap, device))
943 return DriverList[*idx]->alcCaptureStop(device);
944 LastError.store(ALC_INVALID_DEVICE);
947 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) noexcept
949 if(const auto idx = maybe_get(DeviceIfaceMap, device))
950 return DriverList[*idx]->alcCaptureSamples(device, buffer, samples);
951 LastError.store(ALC_INVALID_DEVICE);
955 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) noexcept
957 if(!context)
959 DriverIface *oldiface{GetThreadDriver()};
960 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
961 return ALC_FALSE;
962 SetThreadDriver(nullptr);
963 return ALC_TRUE;
966 ALCenum err{ALC_INVALID_CONTEXT};
967 if(const auto idx = maybe_get(ContextIfaceMap, context).value_or(-1); idx >= 0)
969 if(DriverList[idx]->alcSetThreadContext(context))
971 std::call_once(DriverList[idx]->InitOnceCtx, [idx]{ InitCtxFuncs(*DriverList[idx]); });
973 DriverIface *oldiface{GetThreadDriver()};
974 if(oldiface != DriverList[idx].get())
976 SetThreadDriver(DriverList[idx].get());
977 if(oldiface) oldiface->alcSetThreadContext(nullptr);
979 return ALC_TRUE;
981 err = DriverList[idx]->alcGetError(nullptr);
983 LastError.store(err);
984 return ALC_FALSE;
987 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext() noexcept
989 if(DriverIface *iface{GetThreadDriver()})
990 return iface->alcGetThreadContext();
991 return nullptr;