Add an option to enable direct channels for alffplay
[openal-soft.git] / router / alc.c
bloba8b9c2b26879e173d523560d733bb821132fc84f
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(alEnable),
43 DECL(alDisable),
44 DECL(alIsEnabled),
45 DECL(alGetString),
46 DECL(alGetBooleanv),
47 DECL(alGetIntegerv),
48 DECL(alGetFloatv),
49 DECL(alGetDoublev),
50 DECL(alGetBoolean),
51 DECL(alGetInteger),
52 DECL(alGetFloat),
53 DECL(alGetDouble),
54 DECL(alGetError),
55 DECL(alIsExtensionPresent),
56 DECL(alGetProcAddress),
57 DECL(alGetEnumValue),
58 DECL(alListenerf),
59 DECL(alListener3f),
60 DECL(alListenerfv),
61 DECL(alListeneri),
62 DECL(alListener3i),
63 DECL(alListeneriv),
64 DECL(alGetListenerf),
65 DECL(alGetListener3f),
66 DECL(alGetListenerfv),
67 DECL(alGetListeneri),
68 DECL(alGetListener3i),
69 DECL(alGetListeneriv),
70 DECL(alGenSources),
71 DECL(alDeleteSources),
72 DECL(alIsSource),
73 DECL(alSourcef),
74 DECL(alSource3f),
75 DECL(alSourcefv),
76 DECL(alSourcei),
77 DECL(alSource3i),
78 DECL(alSourceiv),
79 DECL(alGetSourcef),
80 DECL(alGetSource3f),
81 DECL(alGetSourcefv),
82 DECL(alGetSourcei),
83 DECL(alGetSource3i),
84 DECL(alGetSourceiv),
85 DECL(alSourcePlayv),
86 DECL(alSourceStopv),
87 DECL(alSourceRewindv),
88 DECL(alSourcePausev),
89 DECL(alSourcePlay),
90 DECL(alSourceStop),
91 DECL(alSourceRewind),
92 DECL(alSourcePause),
93 DECL(alSourceQueueBuffers),
94 DECL(alSourceUnqueueBuffers),
95 DECL(alGenBuffers),
96 DECL(alDeleteBuffers),
97 DECL(alIsBuffer),
98 DECL(alBufferData),
99 DECL(alBufferf),
100 DECL(alBuffer3f),
101 DECL(alBufferfv),
102 DECL(alBufferi),
103 DECL(alBuffer3i),
104 DECL(alBufferiv),
105 DECL(alGetBufferf),
106 DECL(alGetBuffer3f),
107 DECL(alGetBufferfv),
108 DECL(alGetBufferi),
109 DECL(alGetBuffer3i),
110 DECL(alGetBufferiv),
111 DECL(alDopplerFactor),
112 DECL(alDopplerVelocity),
113 DECL(alSpeedOfSound),
114 DECL(alDistanceModel),
116 #undef DECL
118 #define DECL(x) { #x, (x) }
119 static const struct {
120 const ALCchar *enumName;
121 ALCenum value;
122 } alcEnumerations[] = {
123 DECL(ALC_INVALID),
124 DECL(ALC_FALSE),
125 DECL(ALC_TRUE),
127 DECL(ALC_MAJOR_VERSION),
128 DECL(ALC_MINOR_VERSION),
129 DECL(ALC_ATTRIBUTES_SIZE),
130 DECL(ALC_ALL_ATTRIBUTES),
131 DECL(ALC_DEFAULT_DEVICE_SPECIFIER),
132 DECL(ALC_DEVICE_SPECIFIER),
133 DECL(ALC_ALL_DEVICES_SPECIFIER),
134 DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER),
135 DECL(ALC_EXTENSIONS),
136 DECL(ALC_FREQUENCY),
137 DECL(ALC_REFRESH),
138 DECL(ALC_SYNC),
139 DECL(ALC_MONO_SOURCES),
140 DECL(ALC_STEREO_SOURCES),
141 DECL(ALC_CAPTURE_DEVICE_SPECIFIER),
142 DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER),
143 DECL(ALC_CAPTURE_SAMPLES),
145 DECL(ALC_NO_ERROR),
146 DECL(ALC_INVALID_DEVICE),
147 DECL(ALC_INVALID_CONTEXT),
148 DECL(ALC_INVALID_ENUM),
149 DECL(ALC_INVALID_VALUE),
150 DECL(ALC_OUT_OF_MEMORY),
152 DECL(AL_INVALID),
153 DECL(AL_NONE),
154 DECL(AL_FALSE),
155 DECL(AL_TRUE),
157 DECL(AL_SOURCE_RELATIVE),
158 DECL(AL_CONE_INNER_ANGLE),
159 DECL(AL_CONE_OUTER_ANGLE),
160 DECL(AL_PITCH),
161 DECL(AL_POSITION),
162 DECL(AL_DIRECTION),
163 DECL(AL_VELOCITY),
164 DECL(AL_LOOPING),
165 DECL(AL_BUFFER),
166 DECL(AL_GAIN),
167 DECL(AL_MIN_GAIN),
168 DECL(AL_MAX_GAIN),
169 DECL(AL_ORIENTATION),
170 DECL(AL_REFERENCE_DISTANCE),
171 DECL(AL_ROLLOFF_FACTOR),
172 DECL(AL_CONE_OUTER_GAIN),
173 DECL(AL_MAX_DISTANCE),
174 DECL(AL_SEC_OFFSET),
175 DECL(AL_SAMPLE_OFFSET),
176 DECL(AL_BYTE_OFFSET),
177 DECL(AL_SOURCE_TYPE),
178 DECL(AL_STATIC),
179 DECL(AL_STREAMING),
180 DECL(AL_UNDETERMINED),
182 DECL(AL_SOURCE_STATE),
183 DECL(AL_INITIAL),
184 DECL(AL_PLAYING),
185 DECL(AL_PAUSED),
186 DECL(AL_STOPPED),
188 DECL(AL_BUFFERS_QUEUED),
189 DECL(AL_BUFFERS_PROCESSED),
191 DECL(AL_FORMAT_MONO8),
192 DECL(AL_FORMAT_MONO16),
193 DECL(AL_FORMAT_STEREO8),
194 DECL(AL_FORMAT_STEREO16),
196 DECL(AL_FREQUENCY),
197 DECL(AL_BITS),
198 DECL(AL_CHANNELS),
199 DECL(AL_SIZE),
201 DECL(AL_UNUSED),
202 DECL(AL_PENDING),
203 DECL(AL_PROCESSED),
205 DECL(AL_NO_ERROR),
206 DECL(AL_INVALID_NAME),
207 DECL(AL_INVALID_ENUM),
208 DECL(AL_INVALID_VALUE),
209 DECL(AL_INVALID_OPERATION),
210 DECL(AL_OUT_OF_MEMORY),
212 DECL(AL_VENDOR),
213 DECL(AL_VERSION),
214 DECL(AL_RENDERER),
215 DECL(AL_EXTENSIONS),
217 DECL(AL_DOPPLER_FACTOR),
218 DECL(AL_DOPPLER_VELOCITY),
219 DECL(AL_DISTANCE_MODEL),
220 DECL(AL_SPEED_OF_SOUND),
222 DECL(AL_INVERSE_DISTANCE),
223 DECL(AL_INVERSE_DISTANCE_CLAMPED),
224 DECL(AL_LINEAR_DISTANCE),
225 DECL(AL_LINEAR_DISTANCE_CLAMPED),
226 DECL(AL_EXPONENT_DISTANCE),
227 DECL(AL_EXPONENT_DISTANCE_CLAMPED),
229 #undef DECL
231 static const ALCchar alcNoError[] = "No Error";
232 static const ALCchar alcErrInvalidDevice[] = "Invalid Device";
233 static const ALCchar alcErrInvalidContext[] = "Invalid Context";
234 static const ALCchar alcErrInvalidEnum[] = "Invalid Enum";
235 static const ALCchar alcErrInvalidValue[] = "Invalid Value";
236 static const ALCchar alcErrOutOfMemory[] = "Out of Memory";
237 static const ALCchar alcExtensionList[] =
238 "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE";
240 static const ALCint alcMajorVersion = 1;
241 static const ALCint alcMinorVersion = 1;
244 static almtx_t EnumerationLock;
245 static almtx_t ContextSwitchLock;
247 static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR);
248 static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
249 static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE;
252 typedef struct EnumeratedList {
253 ALCchar *Names;
254 ALCchar *NamesEnd;
255 ALCint *Indicies;
256 ALCsizei IndexSize;
257 } EnumeratedList;
258 static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 };
259 static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 };
260 static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 };
262 static void ClearDeviceList(EnumeratedList *list)
264 al_free(list->Names);
265 list->Names = NULL;
266 list->NamesEnd = NULL;
268 al_free(list->Indicies);
269 list->Indicies = NULL;
270 list->IndexSize = 0;
273 static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx)
275 const ALCchar *name_end = names;
276 ALCsizei count = 0;
277 ALCchar *new_list;
278 ALCint *new_indicies;
279 size_t len;
280 ALCsizei i;
282 if(!name_end)
283 return;
284 while(*name_end)
286 TRACE("Enumerated \"%s\", driver %d\n", name_end, idx);
287 count++;
288 name_end += strlen(name_end)+1;
290 if(names == name_end)
291 return;
293 len = (list->NamesEnd - list->Names) + (name_end - names);
294 new_list = al_calloc(DEF_ALIGN, len + 1);
295 memcpy(new_list, list->Names, list->NamesEnd - list->Names);
296 memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names);
297 al_free(list->Names);
298 list->Names = new_list;
299 list->NamesEnd = list->Names + len;
301 new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count));
302 for(i = 0;i < list->IndexSize;i++)
303 new_indicies[i] = list->Indicies[i];
304 for(i = 0;i < count;i++)
305 new_indicies[list->IndexSize+i] = idx;
306 al_free(list->Indicies);
307 list->Indicies = new_indicies;
308 list->IndexSize += count;
311 static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name)
313 const ALCchar *devnames = list->Names;
314 const ALCint *index = list->Indicies;
316 while(devnames && *devnames)
318 if(strcmp(name, devnames) == 0)
319 return *index;
320 devnames += strlen(devnames)+1;
321 index++;
323 return -1;
326 void InitALC(void)
328 almtx_init(&EnumerationLock, almtx_recursive);
329 almtx_init(&ContextSwitchLock, almtx_plain);
332 void ReleaseALC(void)
334 ClearDeviceList(&DevicesList);
335 ClearDeviceList(&AllDevicesList);
336 ClearDeviceList(&CaptureDevicesList);
338 ResetPtrIntMap(&ContextIfaceMap);
339 ResetPtrIntMap(&DeviceIfaceMap);
341 almtx_destroy(&ContextSwitchLock);
342 almtx_destroy(&EnumerationLock);
346 ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename)
348 ALCdevice *device;
349 ALint idx = 0;
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.
355 if(devicename && (devicename[0] == '\0' ||
356 strcmp(devicename, "DirectSound3D") == 0 ||
357 strcmp(devicename, "DirectSound") == 0 ||
358 strcmp(devicename, "MMSYSTEM") == 0))
359 devicename = NULL;
360 if(devicename)
362 almtx_lock(&EnumerationLock);
363 if(!DevicesList.Names)
364 (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER);
365 idx = GetDriverIndexForName(&DevicesList, devicename);
366 if(idx < 0)
368 if(!AllDevicesList.Names)
369 (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
370 idx = GetDriverIndexForName(&AllDevicesList, devicename);
371 if(idx < 0)
373 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
374 almtx_unlock(&EnumerationLock);
375 return NULL;
378 almtx_unlock(&EnumerationLock);
380 else
382 int i;
383 for(i = 0;i < DriverListSize;i++)
385 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
386 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
388 idx = i;
389 break;
394 device = DriverList[idx].alcOpenDevice(devicename);
395 if(device)
397 if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
399 DriverList[idx].alcCloseDevice(device);
400 device = NULL;
404 return device;
407 ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device)
409 ALint idx;
411 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
413 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
414 return ALC_FALSE;
416 if(!DriverList[idx].alcCloseDevice(device))
417 return ALC_FALSE;
418 RemovePtrIntMapKey(&DeviceIfaceMap, device);
419 return ALC_TRUE;
423 ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist)
425 ALCcontext *context;
426 ALint idx;
428 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
430 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
431 return ALC_FALSE;
433 context = DriverList[idx].alcCreateContext(device, attrlist);
434 if(context)
436 if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR)
438 DriverList[idx].alcDestroyContext(context);
439 context = NULL;
443 return context;
446 ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context)
448 ALint idx = -1;
450 almtx_lock(&ContextSwitchLock);
451 if(context)
453 idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
454 if(idx < 0)
456 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
457 almtx_unlock(&ContextSwitchLock);
458 return ALC_FALSE;
460 if(!DriverList[idx].alcMakeContextCurrent(context))
462 almtx_unlock(&ContextSwitchLock);
463 return ALC_FALSE;
467 /* Unset the context from the old driver if it's different from the new
468 * current one.
470 if(idx < 0)
472 DriverIface *oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL);
473 if(oldiface) oldiface->alcMakeContextCurrent(NULL);
475 else
477 DriverIface *oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]);
478 if(oldiface && oldiface != &DriverList[idx])
479 oldiface->alcMakeContextCurrent(NULL);
481 almtx_unlock(&ContextSwitchLock);
483 return ALC_TRUE;
486 ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context)
488 if(context)
490 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
491 if(idx >= 0)
492 return DriverList[idx].alcProcessContext(context);
494 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
497 ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context)
499 if(context)
501 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
502 if(idx >= 0)
503 return DriverList[idx].alcSuspendContext(context);
505 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
508 ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context)
510 ALint idx;
512 if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0)
514 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
515 return;
518 DriverList[idx].alcDestroyContext(context);
519 RemovePtrIntMapKey(&ContextIfaceMap, context);
522 ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void)
524 DriverIface *iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver);
525 return iface ? iface->alcGetCurrentContext() : NULL;
528 ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context)
530 if(context)
532 ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context);
533 if(idx >= 0)
534 return DriverList[idx].alcGetContextsDevice(context);
536 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT);
537 return NULL;
541 ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device)
543 if(device)
545 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
546 if(idx < 0) return ALC_INVALID_DEVICE;
547 return DriverList[idx].alcGetError(device);
549 return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR);
552 ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname)
554 const char *ptr;
555 size_t len;
557 if(device)
559 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
560 if(idx < 0)
562 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
563 return ALC_FALSE;
565 return DriverList[idx].alcIsExtensionPresent(device, extname);
568 len = strlen(extname);
569 ptr = alcExtensionList;
570 while(ptr && *ptr)
572 if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len])))
573 return ALC_TRUE;
574 if((ptr=strchr(ptr, ' ')) != NULL)
576 do {
577 ++ptr;
578 } while(isspace(*ptr));
581 return ALC_FALSE;
584 ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname)
586 size_t i;
588 if(device)
590 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
591 if(idx < 0)
593 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
594 return NULL;
596 return DriverList[idx].alcGetProcAddress(device, funcname);
599 for(i = 0;i < COUNTOF(alcFunctions);i++)
601 if(strcmp(funcname, alcFunctions[i].funcName) == 0)
602 return alcFunctions[i].address;
604 return NULL;
607 ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname)
609 size_t i;
611 if(device)
613 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
614 if(idx < 0)
616 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
617 return 0;
619 return DriverList[idx].alcGetEnumValue(device, enumname);
622 for(i = 0;i < COUNTOF(alcEnumerations);i++)
624 if(strcmp(enumname, alcEnumerations[i].enumName) == 0)
625 return alcEnumerations[i].value;
627 return 0;
630 ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param)
632 ALsizei i = 0;
634 if(device)
636 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
637 if(idx < 0)
639 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
640 return NULL;
642 return DriverList[idx].alcGetString(device, param);
645 switch(param)
647 case ALC_NO_ERROR:
648 return alcNoError;
649 case ALC_INVALID_ENUM:
650 return alcErrInvalidEnum;
651 case ALC_INVALID_VALUE:
652 return alcErrInvalidValue;
653 case ALC_INVALID_DEVICE:
654 return alcErrInvalidDevice;
655 case ALC_INVALID_CONTEXT:
656 return alcErrInvalidContext;
657 case ALC_OUT_OF_MEMORY:
658 return alcErrOutOfMemory;
659 case ALC_EXTENSIONS:
660 return alcExtensionList;
662 case ALC_DEVICE_SPECIFIER:
663 almtx_lock(&EnumerationLock);
664 ClearDeviceList(&DevicesList);
665 for(i = 0;i < DriverListSize;i++)
667 /* Only enumerate names from drivers that support it. */
668 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
669 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
670 AppendDeviceList(&DevicesList,
671 DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
674 almtx_unlock(&EnumerationLock);
675 return DevicesList.Names;
677 case ALC_ALL_DEVICES_SPECIFIER:
678 almtx_lock(&EnumerationLock);
679 ClearDeviceList(&AllDevicesList);
680 for(i = 0;i < DriverListSize;i++)
682 /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute
683 * standard enumeration.
685 if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
686 AppendDeviceList(&AllDevicesList,
687 DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i
689 else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
690 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
691 AppendDeviceList(&AllDevicesList,
692 DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i
695 almtx_unlock(&EnumerationLock);
696 return AllDevicesList.Names;
698 case ALC_CAPTURE_DEVICE_SPECIFIER:
699 almtx_lock(&EnumerationLock);
700 ClearDeviceList(&CaptureDevicesList);
701 for(i = 0;i < DriverListSize;i++)
703 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
704 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
705 AppendDeviceList(&CaptureDevicesList,
706 DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i
709 almtx_unlock(&EnumerationLock);
710 return CaptureDevicesList.Names;
712 case ALC_DEFAULT_DEVICE_SPECIFIER:
713 for(i = 0;i < DriverListSize;i++)
715 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
716 DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT"))
717 return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
719 return "";
721 case ALC_DEFAULT_ALL_DEVICES_SPECIFIER:
722 for(i = 0;i < DriverListSize;i++)
724 if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT"))
725 return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
727 return "";
729 case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER:
730 for(i = 0;i < DriverListSize;i++)
732 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
733 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
734 return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER);
736 return "";
738 default:
739 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
740 break;
742 return NULL;
745 ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values)
747 if(device)
749 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
750 if(idx < 0)
752 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
753 return;
755 return DriverList[idx].alcGetIntegerv(device, param, size, values);
758 if(size <= 0 || values == NULL)
760 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
761 return;
764 switch(param)
766 case ALC_MAJOR_VERSION:
767 if(size >= 1)
769 values[0] = alcMajorVersion;
770 return;
772 /*fall-through*/
773 case ALC_MINOR_VERSION:
774 if(size >= 1)
776 values[0] = alcMinorVersion;
777 return;
779 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
780 return;
782 case ALC_ATTRIBUTES_SIZE:
783 case ALC_ALL_ATTRIBUTES:
784 case ALC_FREQUENCY:
785 case ALC_REFRESH:
786 case ALC_SYNC:
787 case ALC_MONO_SOURCES:
788 case ALC_STEREO_SOURCES:
789 case ALC_CAPTURE_SAMPLES:
790 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
791 return;
793 default:
794 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM);
795 return;
800 ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize)
802 ALCdevice *device;
803 ALint idx = 0;
805 if(devicename && devicename[0] == '\0')
806 devicename = NULL;
807 if(devicename)
809 almtx_lock(&EnumerationLock);
810 if(!CaptureDevicesList.Names)
811 (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER);
812 idx = GetDriverIndexForName(&CaptureDevicesList, devicename);
813 if(idx < 0)
815 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE);
816 almtx_unlock(&EnumerationLock);
817 return NULL;
819 almtx_unlock(&EnumerationLock);
821 else
823 int i;
824 for(i = 0;i < DriverListSize;i++)
826 if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) ||
827 DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE"))
829 idx = i;
830 break;
835 device = DriverList[idx].alcCaptureOpenDevice(devicename, frequency, format, buffersize);
836 if(device)
838 if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR)
840 DriverList[idx].alcCaptureCloseDevice(device);
841 device = NULL;
845 return device;
848 ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device)
850 ALint idx;
852 if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0)
854 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
855 return ALC_FALSE;
857 if(!DriverList[idx].alcCaptureCloseDevice(device))
858 return ALC_FALSE;
859 RemovePtrIntMapKey(&DeviceIfaceMap, device);
860 return ALC_TRUE;
863 ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device)
865 if(device)
867 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
868 if(idx >= 0)
869 return DriverList[idx].alcCaptureStart(device);
871 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
874 ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device)
876 if(device)
878 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
879 if(idx >= 0)
880 return DriverList[idx].alcCaptureStop(device);
882 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);
885 ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples)
887 if(device)
889 ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device);
890 if(idx >= 0)
891 return DriverList[idx].alcCaptureSamples(device, buffer, samples);
893 ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE);