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