Merge pull request #166 from Ybalrid/betterReadme
[openal-soft.git] / router / alc.c
blob946c7d4c834c459e5acf2c7e01971d03d8286361
2 #include "config.h"
4 #include <stddef.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <stdio.h>
9 #include "AL/alc.h"
10 #include "router.h"
11 #include "almalloc.h"
14 #define COUNTOF(x) (sizeof(x)/sizeof(x[0]))
16 #define DECL(x) { #x, (ALCvoid*)(x) }
17 static const struct {
18 const ALCchar *funcName;
19 ALCvoid *address;
20 } alcFunctions[] = {
21 DECL(alcCreateContext),
22 DECL(alcMakeContextCurrent),
23 DECL(alcProcessContext),
24 DECL(alcSuspendContext),
25 DECL(alcDestroyContext),
26 DECL(alcGetCurrentContext),
27 DECL(alcGetContextsDevice),
28 DECL(alcOpenDevice),
29 DECL(alcCloseDevice),
30 DECL(alcGetError),
31 DECL(alcIsExtensionPresent),
32 DECL(alcGetProcAddress),
33 DECL(alcGetEnumValue),
34 DECL(alcGetString),
35 DECL(alcGetIntegerv),
36 DECL(alcCaptureOpenDevice),
37 DECL(alcCaptureCloseDevice),
38 DECL(alcCaptureStart),
39 DECL(alcCaptureStop),
40 DECL(alcCaptureSamples),
42 DECL(alcSetThreadContext),
43 DECL(alcGetThreadContext),
45 DECL(alEnable),
46 DECL(alDisable),
47 DECL(alIsEnabled),
48 DECL(alGetString),
49 DECL(alGetBooleanv),
50 DECL(alGetIntegerv),
51 DECL(alGetFloatv),
52 DECL(alGetDoublev),
53 DECL(alGetBoolean),
54 DECL(alGetInteger),
55 DECL(alGetFloat),
56 DECL(alGetDouble),
57 DECL(alGetError),
58 DECL(alIsExtensionPresent),
59 DECL(alGetProcAddress),
60 DECL(alGetEnumValue),
61 DECL(alListenerf),
62 DECL(alListener3f),
63 DECL(alListenerfv),
64 DECL(alListeneri),
65 DECL(alListener3i),
66 DECL(alListeneriv),
67 DECL(alGetListenerf),
68 DECL(alGetListener3f),
69 DECL(alGetListenerfv),
70 DECL(alGetListeneri),
71 DECL(alGetListener3i),
72 DECL(alGetListeneriv),
73 DECL(alGenSources),
74 DECL(alDeleteSources),
75 DECL(alIsSource),
76 DECL(alSourcef),
77 DECL(alSource3f),
78 DECL(alSourcefv),
79 DECL(alSourcei),
80 DECL(alSource3i),
81 DECL(alSourceiv),
82 DECL(alGetSourcef),
83 DECL(alGetSource3f),
84 DECL(alGetSourcefv),
85 DECL(alGetSourcei),
86 DECL(alGetSource3i),
87 DECL(alGetSourceiv),
88 DECL(alSourcePlayv),
89 DECL(alSourceStopv),
90 DECL(alSourceRewindv),
91 DECL(alSourcePausev),
92 DECL(alSourcePlay),
93 DECL(alSourceStop),
94 DECL(alSourceRewind),
95 DECL(alSourcePause),
96 DECL(alSourceQueueBuffers),
97 DECL(alSourceUnqueueBuffers),
98 DECL(alGenBuffers),
99 DECL(alDeleteBuffers),
100 DECL(alIsBuffer),
101 DECL(alBufferData),
102 DECL(alBufferf),
103 DECL(alBuffer3f),
104 DECL(alBufferfv),
105 DECL(alBufferi),
106 DECL(alBuffer3i),
107 DECL(alBufferiv),
108 DECL(alGetBufferf),
109 DECL(alGetBuffer3f),
110 DECL(alGetBufferfv),
111 DECL(alGetBufferi),
112 DECL(alGetBuffer3i),
113 DECL(alGetBufferiv),
114 DECL(alDopplerFactor),
115 DECL(alDopplerVelocity),
116 DECL(alSpeedOfSound),
117 DECL(alDistanceModel),
119 #undef DECL
121 #define DECL(x) { #x, (x) }
122 static const struct {
123 const ALCchar *enumName;
124 ALCenum value;
125 } alcEnumerations[] = {
126 DECL(ALC_INVALID),
127 DECL(ALC_FALSE),
128 DECL(ALC_TRUE),
130 DECL(ALC_MAJOR_VERSION),
131 DECL(ALC_MINOR_VERSION),
132 DECL(ALC_ATTRIBUTES_SIZE),
133 DECL(ALC_ALL_ATTRIBUTES),
134 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
135 DECL(ALC_DEVICE_SPECIFIER),
136 DECL(ALC_ALL_DEVICES_SPECIFIER),
137 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
138 DECL(ALC_EXTENSIONS),
139 DECL(ALC_FREQUENCY),
140 DECL(ALC_REFRESH),
141 DECL(ALC_SYNC),
142 DECL(ALC_MONO_SOURCES),
143 DECL(ALC_STEREO_SOURCES),
144 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
145 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
146 DECL(ALC_CAPTURE_SAMPLES),
148 DECL(ALC_NO_ERROR),
149 DECL(ALC_INVALID_DEVICE),
150 DECL(ALC_INVALID_CONTEXT),
151 DECL(ALC_INVALID_ENUM),
152 DECL(ALC_INVALID_VALUE),
153 DECL(ALC_OUT_OF_MEMORY),
155 DECL(AL_INVALID),
156 DECL(AL_NONE),
157 DECL(AL_FALSE),
158 DECL(AL_TRUE),
160 DECL(AL_SOURCE_RELATIVE),
161 DECL(AL_CONE_INNER_ANGLE),
162 DECL(AL_CONE_OUTER_ANGLE),
163 DECL(AL_PITCH),
164 DECL(AL_POSITION),
165 DECL(AL_DIRECTION),
166 DECL(AL_VELOCITY),
167 DECL(AL_LOOPING),
168 DECL(AL_BUFFER),
169 DECL(AL_GAIN),
170 DECL(AL_MIN_GAIN),
171 DECL(AL_MAX_GAIN),
172 DECL(AL_ORIENTATION),
173 DECL(AL_REFERENCE_DISTANCE),
174 DECL(AL_ROLLOFF_FACTOR),
175 DECL(AL_CONE_OUTER_GAIN),
176 DECL(AL_MAX_DISTANCE),
177 DECL(AL_SEC_OFFSET),
178 DECL(AL_SAMPLE_OFFSET),
179 DECL(AL_BYTE_OFFSET),
180 DECL(AL_SOURCE_TYPE),
181 DECL(AL_STATIC),
182 DECL(AL_STREAMING),
183 DECL(AL_UNDETERMINED),
185 DECL(AL_SOURCE_STATE),
186 DECL(AL_INITIAL),
187 DECL(AL_PLAYING),
188 DECL(AL_PAUSED),
189 DECL(AL_STOPPED),
191 DECL(AL_BUFFERS_QUEUED),
192 DECL(AL_BUFFERS_PROCESSED),
194 DECL(AL_FORMAT_MONO8),
195 DECL(AL_FORMAT_MONO16),
196 DECL(AL_FORMAT_STEREO8),
197 DECL(AL_FORMAT_STEREO16),
199 DECL(AL_FREQUENCY),
200 DECL(AL_BITS),
201 DECL(AL_CHANNELS),
202 DECL(AL_SIZE),
204 DECL(AL_UNUSED),
205 DECL(AL_PENDING),
206 DECL(AL_PROCESSED),
208 DECL(AL_NO_ERROR),
209 DECL(AL_INVALID_NAME),
210 DECL(AL_INVALID_ENUM),
211 DECL(AL_INVALID_VALUE),
212 DECL(AL_INVALID_OPERATION),
213 DECL(AL_OUT_OF_MEMORY),
215 DECL(AL_VENDOR),
216 DECL(AL_VERSION),
217 DECL(AL_RENDERER),
218 DECL(AL_EXTENSIONS),
220 DECL(AL_DOPPLER_FACTOR),
221 DECL(AL_DOPPLER_VELOCITY),
222 DECL(AL_DISTANCE_MODEL),
223 DECL(AL_SPEED_OF_SOUND),
225 DECL(AL_INVERSE_DISTANCE),
226 DECL(AL_INVERSE_DISTANCE_CLAMPED),
227 DECL(AL_LINEAR_DISTANCE),
228 DECL(AL_LINEAR_DISTANCE_CLAMPED),
229 DECL(AL_EXPONENT_DISTANCE),
230 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
232 #undef DECL
234 static const ALCchar alcNoError[] = "No Error";
235 static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
236 static const ALCchar alcErrInvalidContext[] = "Invalid Context";
237 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
238 static const ALCchar alcErrInvalidValue[] = "Invalid Value";
239 static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
240 static const ALCchar alcExtensionList[] =
241 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE "
242 "ALC_EXT_thread_local_context";
244 static const ALCint alcMajorVersion = 1;
245 static const ALCint alcMinorVersion = 1;
248 static almtx_t EnumerationLock;
249 static almtx_t ContextSwitchLock;
251 static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR);
252 static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
253 static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
256 typedef struct EnumeratedList {
257 ALCchar *Names;
258 ALCchar *NamesEnd;
259 ALCint *Indicies;
260 ALCsizei IndexSize;
261 } EnumeratedList;
262 static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 };
263 static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 };
264 static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 };
266 static void ClearDeviceList(EnumeratedList *list)
268 al_free(list->Names);
269 list->Names = NULL;
270 list->NamesEnd = NULL;
272 al_free(list->Indicies);
273 list->Indicies = NULL;
274 list->IndexSize = 0;
277 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
279 const ALCchar *name_end = names;
280 ALCsizei count = 0;
281 ALCchar *new_list;
282 ALCint *new_indicies;
283 size_t len;
284 ALCsizei i;
286 if(!name_end)
287 return;
288 while(*name_end)
290 TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
291 count++;
292 name_end += strlen(name_end)+1;
294 if(names == name_end)
295 return;
297 len = (list->NamesEnd - list->Names) + (name_end - names);
298 new_list = al_calloc(DEF_ALIGN, len + 1);
299 memcpy(new_list, list->Names, list->NamesEnd - list->Names);
300 memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names);
301 al_free(list->Names);
302 list->Names = new_list;
303 list->NamesEnd = list->Names + len;
305 new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count));
306 for(i = 0;i < list->IndexSize;i++)
307 new_indicies[i] = list->Indicies[i];
308 for(i = 0;i < count;i++)
309 new_indicies[list->IndexSize+i] = idx;
310 al_free(list->Indicies);
311 list->Indicies = new_indicies;
312 list->IndexSize += count;
315 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
317 const ALCchar *devnames = list->Names;
318 const ALCint *index = list->Indicies;
320 while(devnames && *devnames)
322 if(strcmp(name, devnames) == 0)
323 return *index;
324 devnames += strlen(devnames)+1;
325 index++;
327 return -1;
330 void InitALC(void)
332 almtx_init(&EnumerationLock, almtx_recursive);
333 almtx_init(&ContextSwitchLock, almtx_plain);
336 void ReleaseALC(void)
338 ClearDeviceList(&DevicesList);
339 ClearDeviceList(&AllDevicesList);
340 ClearDeviceList(&CaptureDevicesList);
342 ResetPtrIntMap(&ContextIfaceMap);
343 ResetPtrIntMap(&DeviceIfaceMap);
345 almtx_destroy(&ContextSwitchLock);
346 almtx_destroy(&EnumerationLock);
350 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
352 ALCdevice *device = NULL;
353 ALint idx;
355 /* Prior to the enumeration extension, apps would hardcode these names as a
356 * quality hint for the wrapper driver. Ignore them since there's no sane
357 * way to map them.
359 if(devicename && (devicename[0] == '\0' ||
360 strcmp(devicename, "DirectSound3D") == 0 ||
361 strcmp(devicename, "DirectSound") == 0 ||
362 strcmp(devicename, "MMSYSTEM") == 0))
363 devicename = NULL;
364 if(devicename)
366 almtx_lock(&EnumerationLock);
367 if(!DevicesList.Names)
368 (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
369 idx = GetDriverIndexForName(&DevicesList, devicename);
370 if(idx < 0)
372 if(!AllDevicesList.Names)
373 (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
374 idx = GetDriverIndexForName(&AllDevicesList, devicename);
376 almtx_unlock(&EnumerationLock);
377 if(idx < 0)
379 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
380 TRACE("Failed to find driver for name \"%s\"\n", devicename);
381 return NULL;
383 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
384 device = DriverList[idx].alcOpenDevice(devicename);
386 else
388 int i;
389 for(i = 0;i < DriverListSize;i++)
391 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
392 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
394 idx = i;
395 TRACE("Using default device from driver %d\n", idx);
396 device = DriverList[idx].alcOpenDevice(NULL);
397 break;
402 if(device)
404 if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
406 DriverList[idx].alcCloseDevice(device);
407 device = NULL;
411 return device;
414 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
416 ALint idx;
418 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
420 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
421 return ALC_FALSE;
423 if(!DriverList[idx].alcCloseDevice(device))
424 return ALC_FALSE;
425 RemovePtrIntMapKey(&DeviceIfaceMap, device);
426 return ALC_TRUE;
430 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
432 ALCcontext *context;
433 ALint idx;
435 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
437 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
438 return ALC_FALSE;
440 context = DriverList[idx].alcCreateContext(device, attrlist);
441 if(context)
443 if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR)
445 DriverList[idx].alcDestroyContext(context);
446 context = NULL;
450 return context;
453 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
455 ALint idx = -1;
457 almtx_lock(&ContextSwitchLock);
458 if(context)
460 idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
461 if(idx < 0)
463 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
464 almtx_unlock(&ContextSwitchLock);
465 return ALC_FALSE;
467 if(!DriverList[idx].alcMakeContextCurrent(context))
469 almtx_unlock(&ContextSwitchLock);
470 return ALC_FALSE;
474 /* Unset the context from the old driver if it's different from the new
475 * current one.
477 if(idx < 0)
479 DriverIface *oldiface = altss_get(ThreadCtxDriver);
480 if(oldiface) oldiface->alcSetThreadContext(NULL);
481 oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL);
482 if(oldiface) oldiface->alcMakeContextCurrent(NULL);
484 else
486 DriverIface *oldiface = altss_get(ThreadCtxDriver);
487 if(oldiface && oldiface != &DriverList[idx])
488 oldiface->alcSetThreadContext(NULL);
489 oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]);
490 if(oldiface && oldiface != &DriverList[idx])
491 oldiface->alcMakeContextCurrent(NULL);
493 almtx_unlock(&ContextSwitchLock);
494 altss_set(ThreadCtxDriver, NULL);
496 return ALC_TRUE;
499 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
501 if(context)
503 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
504 if(idx >= 0)
505 return DriverList[idx].alcProcessContext(context);
507 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
510 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
512 if(context)
514 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
515 if(idx >= 0)
516 return DriverList[idx].alcSuspendContext(context);
518 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
521 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
523 ALint idx;
525 if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0)
527 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
528 return;
531 DriverList[idx].alcDestroyContext(context);
532 RemovePtrIntMapKey(&ContextIfaceMap, context);
535 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
537 DriverIface *iface = altss_get(ThreadCtxDriver);
538 if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver);
539 return iface ? iface->alcGetCurrentContext() : NULL;
542 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
544 if(context)
546 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
547 if(idx >= 0)
548 return DriverList[idx].alcGetContextsDevice(context);
550 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
551 return NULL;
555 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
557 if(device)
559 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
560 if(idx < 0) return ALC_INVALID_DEVICE;
561 return DriverList[idx].alcGetError(device);
563 return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR);
566 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
568 const char *ptr;
569 size_t len;
571 if(device)
573 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
574 if(idx < 0)
576 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
577 return ALC_FALSE;
579 return DriverList[idx].alcIsExtensionPresent(device, extname);
582 len = strlen(extname);
583 ptr = alcExtensionList;
584 while(ptr && *ptr)
586 if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
587 return ALC_TRUE;
588 if((ptr=strchr(ptr, ' ')) != NULL)
590 do {
591 ++ptr;
592 } while(isspace(*ptr));
595 return ALC_FALSE;
598 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
600 size_t i;
602 if(device)
604 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
605 if(idx < 0)
607 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
608 return NULL;
610 return DriverList[idx].alcGetProcAddress(device, funcname);
613 for(i = 0;i < COUNTOF(alcFunctions);i++)
615 if(strcmp(funcname, alcFunctions[i].funcName) == 0)
616 return alcFunctions[i].address;
618 return NULL;
621 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
623 size_t i;
625 if(device)
627 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
628 if(idx < 0)
630 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
631 return 0;
633 return DriverList[idx].alcGetEnumValue(device, enumname);
636 for(i = 0;i < COUNTOF(alcEnumerations);i++)
638 if(strcmp(enumname, alcEnumerations[i].enumName) == 0)
639 return alcEnumerations[i].value;
641 return 0;
644 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
646 ALsizei i = 0;
648 if(device)
650 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
651 if(idx < 0)
653 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
654 return NULL;
656 return DriverList[idx].alcGetString(device, param);
659 switch(param)
661 case ALC_NO_ERROR:
662 return alcNoError;
663 case ALC_INVALID_ENUM:
664 return alcErrInvalidEnum;
665 case ALC_INVALID_VALUE:
666 return alcErrInvalidValue;
667 case ALC_INVALID_DEVICE:
668 return alcErrInvalidDevice;
669 case ALC_INVALID_CONTEXT:
670 return alcErrInvalidContext;
671 case ALC_OUT_OF_MEMORY:
672 return alcErrOutOfMemory;
673 case ALC_EXTENSIONS:
674 return alcExtensionList;
676 case ALC_DEVICE_SPECIFIER:
677 almtx_lock(&EnumerationLock);
678 ClearDeviceList(&DevicesList);
679 for(i = 0;i < DriverListSize;i++)
681 /* Only enumerate names from drivers that support it. */
682 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
683 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
684 AppendDeviceList(&DevicesList,
685 DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
688 almtx_unlock(&EnumerationLock);
689 return DevicesList.Names;
691 case ALC_ALL_DEVICES_SPECIFIER:
692 almtx_lock(&EnumerationLock);
693 ClearDeviceList(&AllDevicesList);
694 for(i = 0;i < DriverListSize;i++)
696 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
697 * standard enumeration.
699 if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
700 AppendDeviceList(&AllDevicesList,
701 DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i
703 else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
704 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
705 AppendDeviceList(&AllDevicesList,
706 DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
709 almtx_unlock(&EnumerationLock);
710 return AllDevicesList.Names;
712 case ALC_CAPTURE_DEVICE_SPECIFIER:
713 almtx_lock(&EnumerationLock);
714 ClearDeviceList(&CaptureDevicesList);
715 for(i = 0;i < DriverListSize;i++)
717 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
718 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
719 AppendDeviceList(&CaptureDevicesList,
720 DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i
723 almtx_unlock(&EnumerationLock);
724 return CaptureDevicesList.Names;
726 case ALC_DEFAULT_DEVICE_SPECIFIER:
727 for(i = 0;i < DriverListSize;i++)
729 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
730 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
731 return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
733 return "";
735 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
736 for(i = 0;i < DriverListSize;i++)
738 if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
739 return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
741 return "";
743 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
744 for(i = 0;i < DriverListSize;i++)
746 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
747 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
748 return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
750 return "";
752 default:
753 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
754 break;
756 return NULL;
759 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
761 if(device)
763 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
764 if(idx < 0)
766 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
767 return;
769 return DriverList[idx].alcGetIntegerv(device, param, size, values);
772 if(size <= 0 || values == NULL)
774 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
775 return;
778 switch(param)
780 case ALC_MAJOR_VERSION:
781 if(size >= 1)
783 values[0] = alcMajorVersion;
784 return;
786 /*fall-through*/
787 case ALC_MINOR_VERSION:
788 if(size >= 1)
790 values[0] = alcMinorVersion;
791 return;
793 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
794 return;
796 case ALC_ATTRIBUTES_SIZE:
797 case ALC_ALL_ATTRIBUTES:
798 case ALC_FREQUENCY:
799 case ALC_REFRESH:
800 case ALC_SYNC:
801 case ALC_MONO_SOURCES:
802 case ALC_STEREO_SOURCES:
803 case ALC_CAPTURE_SAMPLES:
804 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
805 return;
807 default:
808 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
809 return;
814 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
816 ALCdevice *device = NULL;
817 ALint idx;
819 if(devicename && devicename[0] == '\0')
820 devicename = NULL;
821 if(devicename)
823 almtx_lock(&EnumerationLock);
824 if(!CaptureDevicesList.Names)
825 (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
826 idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
827 almtx_unlock(&EnumerationLock);
828 if(idx < 0)
830 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
831 TRACE("Failed to find driver for name \"%s\"\n", devicename);
832 return NULL;
834 TRACE("Found driver %d for name \"%s\"\n", idx, devicename);
835 device = DriverList[idx].alcCaptureOpenDevice(
836 devicename, frequency, format, buffersize
839 else
841 int i;
842 for(i = 0;i < DriverListSize;i++)
844 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
845 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
847 idx = i;
848 TRACE("Using default capture device from driver %d\n", idx);
849 device = DriverList[idx].alcCaptureOpenDevice(
850 NULL, frequency, format, buffersize
852 break;
857 if(device)
859 if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
861 DriverList[idx].alcCaptureCloseDevice(device);
862 device = NULL;
866 return device;
869 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
871 ALint idx;
873 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
875 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
876 return ALC_FALSE;
878 if(!DriverList[idx].alcCaptureCloseDevice(device))
879 return ALC_FALSE;
880 RemovePtrIntMapKey(&DeviceIfaceMap, device);
881 return ALC_TRUE;
884 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
886 if(device)
888 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
889 if(idx >= 0)
890 return DriverList[idx].alcCaptureStart(device);
892 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
895 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
897 if(device)
899 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
900 if(idx >= 0)
901 return DriverList[idx].alcCaptureStop(device);
903 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
906 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
908 if(device)
910 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
911 if(idx >= 0)
912 return DriverList[idx].alcCaptureSamples(device, buffer, samples);
914 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
918 ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context)
920 ALCenum err = ALC_INVALID_CONTEXT;
921 ALint idx;
923 if(!context)
925 DriverIface *oldiface = altss_get(ThreadCtxDriver);
926 if(oldiface && !oldiface->alcSetThreadContext(NULL))
927 return ALC_FALSE;
928 altss_set(ThreadCtxDriver, NULL);
929 return ALC_TRUE;
932 idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
933 if(idx >= 0)
935 if(DriverList[idx].alcSetThreadContext(context))
937 DriverIface *oldiface = altss_get(ThreadCtxDriver);
938 if(oldiface != &DriverList[idx])
940 altss_set(ThreadCtxDriver, &DriverList[idx]);
941 if(oldiface) oldiface->alcSetThreadContext(NULL);
943 return ALC_TRUE;
945 err = DriverList[idx].alcGetError(NULL);
947 ATOMIC_STORE_SEQ(&LastError, err);
948 return ALC_FALSE;
951 ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void)
953 DriverIface *iface = altss_get(ThreadCtxDriver);
954 if(iface) return iface->alcGetThreadContext();
955 return NULL;