Clean up some unnecessary includes
[openal-soft.git] / router / alc.cpp
blobc99e7c93832eef67273cbd9b1e260f85ae87e0d9
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 ALCchar *funcName;
21 ALCvoid *address;
23 static const std::array<FuncExportEntry,95> 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::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)
328 { std::lock_guard<std::mutex> _{EnumerationLock};
329 if(DevicesList.Names.empty())
330 (void)alcGetString(nullptr, ALC_DEVICE_SPECIFIER);
331 idx = GetDriverIndexForName(&DevicesList, devicename);
332 if(idx < 0)
334 if(AllDevicesList.Names.empty())
335 (void)alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER);
336 idx = GetDriverIndexForName(&AllDevicesList, devicename);
340 if(idx < 0)
342 LastError.store(ALC_INVALID_VALUE);
343 TRACE("Failed to find driver for name \"%s\"\n", devicename);
344 return nullptr;
346 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
347 device = DriverList[idx].alcOpenDevice(devicename);
349 else
351 for(const auto &drv : DriverList)
353 if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
354 drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
356 TRACE("Using default device from driver %d\n", idx);
357 device = drv.alcOpenDevice(nullptr);
358 break;
360 ++idx;
364 if(device)
366 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
368 DriverList[idx].alcCloseDevice(device);
369 device = nullptr;
373 return device;
376 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
378 ALint idx;
380 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
382 LastError.store(ALC_INVALID_DEVICE);
383 return ALC_FALSE;
385 if(!DriverList[idx].alcCloseDevice(device))
386 return ALC_FALSE;
387 DeviceIfaceMap.removeByKey(device);
388 return ALC_TRUE;
392 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
394 ALCcontext *context;
395 ALint idx;
397 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
399 LastError.store(ALC_INVALID_DEVICE);
400 return nullptr;
402 context = DriverList[idx].alcCreateContext(device, attrlist);
403 if(context)
405 if(ContextIfaceMap.insert(context, idx) != ALC_NO_ERROR)
407 DriverList[idx].alcDestroyContext(context);
408 context = nullptr;
412 return context;
415 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
417 ALint idx = -1;
419 std::lock_guard<std::mutex> _{ContextSwitchLock};
420 if(context)
422 idx = ContextIfaceMap.lookupByKey(context);
423 if(idx < 0)
425 LastError.store(ALC_INVALID_CONTEXT);
426 return ALC_FALSE;
428 if(!DriverList[idx].alcMakeContextCurrent(context))
429 return ALC_FALSE;
432 /* Unset the context from the old driver if it's different from the new
433 * current one.
435 if(idx < 0)
437 DriverIface *oldiface = ThreadCtxDriver;
438 if(oldiface) oldiface->alcSetThreadContext(nullptr);
439 oldiface = CurrentCtxDriver.exchange(nullptr);
440 if(oldiface) oldiface->alcMakeContextCurrent(nullptr);
442 else
444 DriverIface *oldiface = ThreadCtxDriver;
445 if(oldiface && oldiface != &DriverList[idx])
446 oldiface->alcSetThreadContext(nullptr);
447 oldiface = CurrentCtxDriver.exchange(&DriverList[idx]);
448 if(oldiface && oldiface != &DriverList[idx])
449 oldiface->alcMakeContextCurrent(nullptr);
451 ThreadCtxDriver = nullptr;
453 return ALC_TRUE;
456 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
458 if(context)
460 ALint idx = ContextIfaceMap.lookupByKey(context);
461 if(idx >= 0)
462 return DriverList[idx].alcProcessContext(context);
464 LastError.store(ALC_INVALID_CONTEXT);
467 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
469 if(context)
471 ALint idx = ContextIfaceMap.lookupByKey(context);
472 if(idx >= 0)
473 return DriverList[idx].alcSuspendContext(context);
475 LastError.store(ALC_INVALID_CONTEXT);
478 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
480 ALint idx;
482 if(!context || (idx=ContextIfaceMap.lookupByKey(context)) < 0)
484 LastError.store(ALC_INVALID_CONTEXT);
485 return;
488 DriverList[idx].alcDestroyContext(context);
489 ContextIfaceMap.removeByKey(context);
492 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
494 DriverIface *iface = ThreadCtxDriver;
495 if(!iface) iface = CurrentCtxDriver.load();
496 return iface ? iface->alcGetCurrentContext() : nullptr;
499 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
501 if(context)
503 ALint idx = ContextIfaceMap.lookupByKey(context);
504 if(idx >= 0)
505 return DriverList[idx].alcGetContextsDevice(context);
507 LastError.store(ALC_INVALID_CONTEXT);
508 return nullptr;
512 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
514 if(device)
516 ALint idx = DeviceIfaceMap.lookupByKey(device);
517 if(idx < 0) return ALC_INVALID_DEVICE;
518 return DriverList[idx].alcGetError(device);
520 return LastError.exchange(ALC_NO_ERROR);
523 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
525 const char *ptr;
526 size_t len;
528 if(device)
530 ALint idx = DeviceIfaceMap.lookupByKey(device);
531 if(idx < 0)
533 LastError.store(ALC_INVALID_DEVICE);
534 return ALC_FALSE;
536 return DriverList[idx].alcIsExtensionPresent(device, extname);
539 len = strlen(extname);
540 ptr = alcExtensionList;
541 while(ptr && *ptr)
543 if(al::strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
544 return ALC_TRUE;
545 if((ptr=strchr(ptr, ' ')) != nullptr)
547 do {
548 ++ptr;
549 } while(isspace(*ptr));
552 return ALC_FALSE;
555 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
557 if(device)
559 ALint idx = DeviceIfaceMap.lookupByKey(device);
560 if(idx < 0)
562 LastError.store(ALC_INVALID_DEVICE);
563 return nullptr;
565 return DriverList[idx].alcGetProcAddress(device, funcname);
568 auto iter = std::find_if(alcFunctions.cbegin(), alcFunctions.cend(),
569 [funcname](const FuncExportEntry &entry) -> bool
570 { return strcmp(funcname, entry.funcName) == 0; }
572 return (iter != alcFunctions.cend()) ? iter->address : nullptr;
575 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
577 if(device)
579 ALint idx = DeviceIfaceMap.lookupByKey(device);
580 if(idx < 0)
582 LastError.store(ALC_INVALID_DEVICE);
583 return 0;
585 return DriverList[idx].alcGetEnumValue(device, enumname);
588 auto iter = std::find_if(alcEnumerations.cbegin(), alcEnumerations.cend(),
589 [enumname](const EnumExportEntry &entry) -> bool
590 { return strcmp(enumname, entry.enumName) == 0; }
592 return (iter != alcEnumerations.cend()) ? iter->value : 0;
595 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
597 if(device)
599 ALint idx = DeviceIfaceMap.lookupByKey(device);
600 if(idx < 0)
602 LastError.store(ALC_INVALID_DEVICE);
603 return nullptr;
605 return DriverList[idx].alcGetString(device, param);
608 switch(param)
610 case ALC_NO_ERROR:
611 return alcNoError;
612 case ALC_INVALID_ENUM:
613 return alcErrInvalidEnum;
614 case ALC_INVALID_VALUE:
615 return alcErrInvalidValue;
616 case ALC_INVALID_DEVICE:
617 return alcErrInvalidDevice;
618 case ALC_INVALID_CONTEXT:
619 return alcErrInvalidContext;
620 case ALC_OUT_OF_MEMORY:
621 return alcErrOutOfMemory;
622 case ALC_EXTENSIONS:
623 return alcExtensionList;
625 case ALC_DEVICE_SPECIFIER:
626 { std::lock_guard<std::mutex> _{EnumerationLock};
627 DevicesList.clear();
628 ALint idx = 0;
629 for(const auto &drv : DriverList)
631 /* Only enumerate names from drivers that support it. */
632 if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
633 drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
634 AppendDeviceList(&DevicesList,
635 drv.alcGetString(nullptr, ALC_DEVICE_SPECIFIER), idx
637 idx++;
639 /* Ensure the list is double-null termianted. */
640 if(DevicesList.Names.empty())
641 DevicesList.Names.emplace_back('\0');
642 DevicesList.Names.emplace_back('\0');
643 return DevicesList.Names.data();
646 case ALC_ALL_DEVICES_SPECIFIER:
647 { std::lock_guard<std::mutex> _{EnumerationLock};
648 AllDevicesList.clear();
649 ALint idx = 0;
650 for(const auto &drv : DriverList)
652 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
653 * standard enumeration.
655 if(drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT"))
656 AppendDeviceList(&AllDevicesList,
657 drv.alcGetString(nullptr, ALC_ALL_DEVICES_SPECIFIER), idx
659 else if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
660 drv.alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT"))
661 AppendDeviceList(&AllDevicesList,
662 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:
674 { std::lock_guard<std::mutex> _{EnumerationLock};
675 CaptureDevicesList.clear();
676 ALint idx = 0;
677 for(const auto &drv : DriverList)
679 if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
680 drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
681 AppendDeviceList(&CaptureDevicesList,
682 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; }
713 if(iter != DriverList.cend())
714 return iter->alcGetString(nullptr, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
715 return "";
718 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
720 auto iter = std::find_if(DriverList.cbegin(), DriverList.cend(),
721 [](const DriverIface &drv) -> bool
723 return drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
724 drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE");
727 if(iter != DriverList.cend())
728 return iter->alcGetString(nullptr, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
729 return "";
732 default:
733 LastError.store(ALC_INVALID_ENUM);
734 break;
736 return nullptr;
739 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
741 if(device)
743 ALint idx = DeviceIfaceMap.lookupByKey(device);
744 if(idx < 0)
746 LastError.store(ALC_INVALID_DEVICE);
747 return;
749 return DriverList[idx].alcGetIntegerv(device, param, size, values);
752 if(size <= 0 || values == nullptr)
754 LastError.store(ALC_INVALID_VALUE);
755 return;
758 switch(param)
760 case ALC_MAJOR_VERSION:
761 if(size >= 1)
763 values[0] = alcMajorVersion;
764 return;
766 /*fall-through*/
767 case ALC_MINOR_VERSION:
768 if(size >= 1)
770 values[0] = alcMinorVersion;
771 return;
773 LastError.store(ALC_INVALID_VALUE);
774 return;
776 case ALC_ATTRIBUTES_SIZE:
777 case ALC_ALL_ATTRIBUTES:
778 case ALC_FREQUENCY:
779 case ALC_REFRESH:
780 case ALC_SYNC:
781 case ALC_MONO_SOURCES:
782 case ALC_STEREO_SOURCES:
783 case ALC_CAPTURE_SAMPLES:
784 LastError.store(ALC_INVALID_DEVICE);
785 return;
787 default:
788 LastError.store(ALC_INVALID_ENUM);
789 return;
794 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
796 ALCdevice *device = nullptr;
797 ALint idx = 0;
799 if(devicename && devicename[0] == '\0')
800 devicename = nullptr;
801 if(devicename)
803 { std::lock_guard<std::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(
817 devicename, frequency, format, buffersize
820 else
822 for(const auto &drv : DriverList)
824 if(drv.ALCVer >= MAKE_ALC_VER(1, 1) ||
825 drv.alcIsExtensionPresent(nullptr, "ALC_EXT_CAPTURE"))
827 TRACE("Using default capture device from driver %d\n", idx);
828 device = drv.alcCaptureOpenDevice(
829 nullptr, frequency, format, buffersize
831 break;
833 ++idx;
837 if(device)
839 if(DeviceIfaceMap.insert(device, idx) != ALC_NO_ERROR)
841 DriverList[idx].alcCaptureCloseDevice(device);
842 device = nullptr;
846 return device;
849 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
851 ALint idx;
853 if(!device || (idx=DeviceIfaceMap.lookupByKey(device)) < 0)
855 LastError.store(ALC_INVALID_DEVICE);
856 return ALC_FALSE;
858 if(!DriverList[idx].alcCaptureCloseDevice(device))
859 return ALC_FALSE;
860 DeviceIfaceMap.removeByKey(device);
861 return ALC_TRUE;
864 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
866 if(device)
868 ALint idx = DeviceIfaceMap.lookupByKey(device);
869 if(idx >= 0)
870 return DriverList[idx].alcCaptureStart(device);
872 LastError.store(ALC_INVALID_DEVICE);
875 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
877 if(device)
879 ALint idx = DeviceIfaceMap.lookupByKey(device);
880 if(idx >= 0)
881 return DriverList[idx].alcCaptureStop(device);
883 LastError.store(ALC_INVALID_DEVICE);
886 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
888 if(device)
890 ALint idx = DeviceIfaceMap.lookupByKey(device);
891 if(idx >= 0)
892 return DriverList[idx].alcCaptureSamples(device, buffer, samples);
894 LastError.store(ALC_INVALID_DEVICE);
898 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
900 ALCenum err = ALC_INVALID_CONTEXT;
901 ALint idx;
903 if(!context)
905 DriverIface *oldiface = ThreadCtxDriver;
906 if(oldiface && !oldiface->alcSetThreadContext(nullptr))
907 return ALC_FALSE;
908 ThreadCtxDriver = nullptr;
909 return ALC_TRUE;
912 idx = ContextIfaceMap.lookupByKey(context);
913 if(idx >= 0)
915 if(DriverList[idx].alcSetThreadContext(context))
917 DriverIface *oldiface = ThreadCtxDriver;
918 if(oldiface != &DriverList[idx])
920 ThreadCtxDriver = &DriverList[idx];
921 if(oldiface) oldiface->alcSetThreadContext(nullptr);
923 return ALC_TRUE;
925 err = DriverList[idx].alcGetError(nullptr);
927 LastError.store(err);
928 return ALC_FALSE;
931 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
933 DriverIface *iface = ThreadCtxDriver;
934 if(iface) return iface->alcGetThreadContext();
935 return nullptr;