diff options
Diffstat (limited to 'router')
-rw-r--r-- | router/al.c | 132 | ||||
-rw-r--r-- | router/alc.c | 956 | ||||
-rw-r--r-- | router/router.c | 537 | ||||
-rw-r--r-- | router/router.h | 197 |
4 files changed, 1822 insertions, 0 deletions
diff --git a/router/al.c b/router/al.c new file mode 100644 index 00000000..8dd888d9 --- /dev/null +++ b/router/al.c @@ -0,0 +1,132 @@ + +#include "config.h" + +#include <stddef.h> + +#include "AL/al.h" +#include "router.h" + + +atomic_DriverIfacePtr CurrentCtxDriver = ATOMIC_INIT_STATIC(NULL); + +#define DECL_THUNK1(R,n,T1) AL_API R AL_APIENTRY n(T1 a) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a); \ +} +#define DECL_THUNK2(R,n,T1,T2) AL_API R AL_APIENTRY n(T1 a, T2 b) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b); \ +} +#define DECL_THUNK3(R,n,T1,T2,T3) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c); \ +} +#define DECL_THUNK4(R,n,T1,T2,T3,T4) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d); \ +} +#define DECL_THUNK5(R,n,T1,T2,T3,T4,T5) AL_API R AL_APIENTRY n(T1 a, T2 b, T3 c, T4 d, T5 e) \ +{ \ + DriverIface *iface = altss_get(ThreadCtxDriver); \ + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire);\ + return iface->n(a, b, c, d, e); \ +} + + +/* Ugly hack for some apps calling alGetError without a current context, and + * expecting it to be AL_NO_ERROR. + */ +AL_API ALenum AL_APIENTRY alGetError(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(!iface) iface = ATOMIC_LOAD(&CurrentCtxDriver, almemory_order_acquire); + return iface ? iface->alGetError() : AL_NO_ERROR; +} + + +DECL_THUNK1(void, alDopplerFactor, ALfloat) +DECL_THUNK1(void, alDopplerVelocity, ALfloat) +DECL_THUNK1(void, alSpeedOfSound, ALfloat) +DECL_THUNK1(void, alDistanceModel, ALenum) + +DECL_THUNK1(void, alEnable, ALenum) +DECL_THUNK1(void, alDisable, ALenum) +DECL_THUNK1(ALboolean, alIsEnabled, ALenum) + +DECL_THUNK1(const ALchar*, alGetString, ALenum) +DECL_THUNK2(void, alGetBooleanv, ALenum, ALboolean*) +DECL_THUNK2(void, alGetIntegerv, ALenum, ALint*) +DECL_THUNK2(void, alGetFloatv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetDoublev, ALenum, ALdouble*) +DECL_THUNK1(ALboolean, alGetBoolean, ALenum) +DECL_THUNK1(ALint, alGetInteger, ALenum) +DECL_THUNK1(ALfloat, alGetFloat, ALenum) +DECL_THUNK1(ALdouble, alGetDouble, ALenum) + +DECL_THUNK1(ALboolean, alIsExtensionPresent, const ALchar*) +DECL_THUNK1(void*, alGetProcAddress, const ALchar*) +DECL_THUNK1(ALenum, alGetEnumValue, const ALchar*) + +DECL_THUNK2(void, alListenerf, ALenum, ALfloat) +DECL_THUNK4(void, alListener3f, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK2(void, alListenerfv, ALenum, const ALfloat*) +DECL_THUNK2(void, alListeneri, ALenum, ALint) +DECL_THUNK4(void, alListener3i, ALenum, ALint, ALint, ALint) +DECL_THUNK2(void, alListeneriv, ALenum, const ALint*) +DECL_THUNK2(void, alGetListenerf, ALenum, ALfloat*) +DECL_THUNK4(void, alGetListener3f, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK2(void, alGetListenerfv, ALenum, ALfloat*) +DECL_THUNK2(void, alGetListeneri, ALenum, ALint*) +DECL_THUNK4(void, alGetListener3i, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK2(void, alGetListeneriv, ALenum, ALint*) + +DECL_THUNK2(void, alGenSources, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteSources, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsSource, ALuint) +DECL_THUNK3(void, alSourcef, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alSource3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alSourcefv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alSourcei, ALuint, ALenum, ALint) +DECL_THUNK5(void, alSource3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alSourceiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetSourcef, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetSource3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetSourcefv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetSourcei, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetSource3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetSourceiv, ALuint, ALenum, ALint*) +DECL_THUNK2(void, alSourcePlayv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceStopv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourceRewindv, ALsizei, const ALuint*) +DECL_THUNK2(void, alSourcePausev, ALsizei, const ALuint*) +DECL_THUNK1(void, alSourcePlay, ALuint) +DECL_THUNK1(void, alSourceStop, ALuint) +DECL_THUNK1(void, alSourceRewind, ALuint) +DECL_THUNK1(void, alSourcePause, ALuint) +DECL_THUNK3(void, alSourceQueueBuffers, ALuint, ALsizei, const ALuint*) +DECL_THUNK3(void, alSourceUnqueueBuffers, ALuint, ALsizei, ALuint*) + +DECL_THUNK2(void, alGenBuffers, ALsizei, ALuint*) +DECL_THUNK2(void, alDeleteBuffers, ALsizei, const ALuint*) +DECL_THUNK1(ALboolean, alIsBuffer, ALuint) +DECL_THUNK3(void, alBufferf, ALuint, ALenum, ALfloat) +DECL_THUNK5(void, alBuffer3f, ALuint, ALenum, ALfloat, ALfloat, ALfloat) +DECL_THUNK3(void, alBufferfv, ALuint, ALenum, const ALfloat*) +DECL_THUNK3(void, alBufferi, ALuint, ALenum, ALint) +DECL_THUNK5(void, alBuffer3i, ALuint, ALenum, ALint, ALint, ALint) +DECL_THUNK3(void, alBufferiv, ALuint, ALenum, const ALint*) +DECL_THUNK3(void, alGetBufferf, ALuint, ALenum, ALfloat*) +DECL_THUNK5(void, alGetBuffer3f, ALuint, ALenum, ALfloat*, ALfloat*, ALfloat*) +DECL_THUNK3(void, alGetBufferfv, ALuint, ALenum, ALfloat*) +DECL_THUNK3(void, alGetBufferi, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alGetBuffer3i, ALuint, ALenum, ALint*, ALint*, ALint*) +DECL_THUNK3(void, alGetBufferiv, ALuint, ALenum, ALint*) +DECL_THUNK5(void, alBufferData, ALuint, ALenum, const ALvoid*, ALsizei, ALsizei) diff --git a/router/alc.c b/router/alc.c new file mode 100644 index 00000000..946c7d4c --- /dev/null +++ b/router/alc.c @@ -0,0 +1,956 @@ + +#include "config.h" + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "AL/alc.h" +#include "router.h" +#include "almalloc.h" + + +#define COUNTOF(x) (sizeof(x)/sizeof(x[0])) + +#define DECL(x) { #x, (ALCvoid*)(x) } +static const struct { + const ALCchar *funcName; + ALCvoid *address; +} alcFunctions[] = { + DECL(alcCreateContext), + DECL(alcMakeContextCurrent), + DECL(alcProcessContext), + DECL(alcSuspendContext), + DECL(alcDestroyContext), + DECL(alcGetCurrentContext), + DECL(alcGetContextsDevice), + DECL(alcOpenDevice), + DECL(alcCloseDevice), + DECL(alcGetError), + DECL(alcIsExtensionPresent), + DECL(alcGetProcAddress), + DECL(alcGetEnumValue), + DECL(alcGetString), + DECL(alcGetIntegerv), + DECL(alcCaptureOpenDevice), + DECL(alcCaptureCloseDevice), + DECL(alcCaptureStart), + DECL(alcCaptureStop), + DECL(alcCaptureSamples), + + DECL(alcSetThreadContext), + DECL(alcGetThreadContext), + + DECL(alEnable), + DECL(alDisable), + DECL(alIsEnabled), + DECL(alGetString), + DECL(alGetBooleanv), + DECL(alGetIntegerv), + DECL(alGetFloatv), + DECL(alGetDoublev), + DECL(alGetBoolean), + DECL(alGetInteger), + DECL(alGetFloat), + DECL(alGetDouble), + DECL(alGetError), + DECL(alIsExtensionPresent), + DECL(alGetProcAddress), + DECL(alGetEnumValue), + DECL(alListenerf), + DECL(alListener3f), + DECL(alListenerfv), + DECL(alListeneri), + DECL(alListener3i), + DECL(alListeneriv), + DECL(alGetListenerf), + DECL(alGetListener3f), + DECL(alGetListenerfv), + DECL(alGetListeneri), + DECL(alGetListener3i), + DECL(alGetListeneriv), + DECL(alGenSources), + DECL(alDeleteSources), + DECL(alIsSource), + DECL(alSourcef), + DECL(alSource3f), + DECL(alSourcefv), + DECL(alSourcei), + DECL(alSource3i), + DECL(alSourceiv), + DECL(alGetSourcef), + DECL(alGetSource3f), + DECL(alGetSourcefv), + DECL(alGetSourcei), + DECL(alGetSource3i), + DECL(alGetSourceiv), + DECL(alSourcePlayv), + DECL(alSourceStopv), + DECL(alSourceRewindv), + DECL(alSourcePausev), + DECL(alSourcePlay), + DECL(alSourceStop), + DECL(alSourceRewind), + DECL(alSourcePause), + DECL(alSourceQueueBuffers), + DECL(alSourceUnqueueBuffers), + DECL(alGenBuffers), + DECL(alDeleteBuffers), + DECL(alIsBuffer), + DECL(alBufferData), + DECL(alBufferf), + DECL(alBuffer3f), + DECL(alBufferfv), + DECL(alBufferi), + DECL(alBuffer3i), + DECL(alBufferiv), + DECL(alGetBufferf), + DECL(alGetBuffer3f), + DECL(alGetBufferfv), + DECL(alGetBufferi), + DECL(alGetBuffer3i), + DECL(alGetBufferiv), + DECL(alDopplerFactor), + DECL(alDopplerVelocity), + DECL(alSpeedOfSound), + DECL(alDistanceModel), +}; +#undef DECL + +#define DECL(x) { #x, (x) } +static const struct { + const ALCchar *enumName; + ALCenum value; +} alcEnumerations[] = { + DECL(ALC_INVALID), + DECL(ALC_FALSE), + DECL(ALC_TRUE), + + DECL(ALC_MAJOR_VERSION), + DECL(ALC_MINOR_VERSION), + DECL(ALC_ATTRIBUTES_SIZE), + DECL(ALC_ALL_ATTRIBUTES), + DECL(ALC_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_DEVICE_SPECIFIER), + DECL(ALC_ALL_DEVICES_SPECIFIER), + DECL(ALC_DEFAULT_ALL_DEVICES_SPECIFIER), + DECL(ALC_EXTENSIONS), + DECL(ALC_FREQUENCY), + DECL(ALC_REFRESH), + DECL(ALC_SYNC), + DECL(ALC_MONO_SOURCES), + DECL(ALC_STEREO_SOURCES), + DECL(ALC_CAPTURE_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER), + DECL(ALC_CAPTURE_SAMPLES), + + DECL(ALC_NO_ERROR), + DECL(ALC_INVALID_DEVICE), + DECL(ALC_INVALID_CONTEXT), + DECL(ALC_INVALID_ENUM), + DECL(ALC_INVALID_VALUE), + DECL(ALC_OUT_OF_MEMORY), + + DECL(AL_INVALID), + DECL(AL_NONE), + DECL(AL_FALSE), + DECL(AL_TRUE), + + DECL(AL_SOURCE_RELATIVE), + DECL(AL_CONE_INNER_ANGLE), + DECL(AL_CONE_OUTER_ANGLE), + DECL(AL_PITCH), + DECL(AL_POSITION), + DECL(AL_DIRECTION), + DECL(AL_VELOCITY), + DECL(AL_LOOPING), + DECL(AL_BUFFER), + DECL(AL_GAIN), + DECL(AL_MIN_GAIN), + DECL(AL_MAX_GAIN), + DECL(AL_ORIENTATION), + DECL(AL_REFERENCE_DISTANCE), + DECL(AL_ROLLOFF_FACTOR), + DECL(AL_CONE_OUTER_GAIN), + DECL(AL_MAX_DISTANCE), + DECL(AL_SEC_OFFSET), + DECL(AL_SAMPLE_OFFSET), + DECL(AL_BYTE_OFFSET), + DECL(AL_SOURCE_TYPE), + DECL(AL_STATIC), + DECL(AL_STREAMING), + DECL(AL_UNDETERMINED), + + DECL(AL_SOURCE_STATE), + DECL(AL_INITIAL), + DECL(AL_PLAYING), + DECL(AL_PAUSED), + DECL(AL_STOPPED), + + DECL(AL_BUFFERS_QUEUED), + DECL(AL_BUFFERS_PROCESSED), + + DECL(AL_FORMAT_MONO8), + DECL(AL_FORMAT_MONO16), + DECL(AL_FORMAT_STEREO8), + DECL(AL_FORMAT_STEREO16), + + DECL(AL_FREQUENCY), + DECL(AL_BITS), + DECL(AL_CHANNELS), + DECL(AL_SIZE), + + DECL(AL_UNUSED), + DECL(AL_PENDING), + DECL(AL_PROCESSED), + + DECL(AL_NO_ERROR), + DECL(AL_INVALID_NAME), + DECL(AL_INVALID_ENUM), + DECL(AL_INVALID_VALUE), + DECL(AL_INVALID_OPERATION), + DECL(AL_OUT_OF_MEMORY), + + DECL(AL_VENDOR), + DECL(AL_VERSION), + DECL(AL_RENDERER), + DECL(AL_EXTENSIONS), + + DECL(AL_DOPPLER_FACTOR), + DECL(AL_DOPPLER_VELOCITY), + DECL(AL_DISTANCE_MODEL), + DECL(AL_SPEED_OF_SOUND), + + DECL(AL_INVERSE_DISTANCE), + DECL(AL_INVERSE_DISTANCE_CLAMPED), + DECL(AL_LINEAR_DISTANCE), + DECL(AL_LINEAR_DISTANCE_CLAMPED), + DECL(AL_EXPONENT_DISTANCE), + DECL(AL_EXPONENT_DISTANCE_CLAMPED), +}; +#undef DECL + +static const ALCchar alcNoError[] = "No Error"; +static const ALCchar alcErrInvalidDevice[] = "Invalid Device"; +static const ALCchar alcErrInvalidContext[] = "Invalid Context"; +static const ALCchar alcErrInvalidEnum[] = "Invalid Enum"; +static const ALCchar alcErrInvalidValue[] = "Invalid Value"; +static const ALCchar alcErrOutOfMemory[] = "Out of Memory"; +static const ALCchar alcExtensionList[] = + "ALC_ENUMERATE_ALL_EXT ALC_ENUMERATION_EXT ALC_EXT_CAPTURE " + "ALC_EXT_thread_local_context"; + +static const ALCint alcMajorVersion = 1; +static const ALCint alcMinorVersion = 1; + + +static almtx_t EnumerationLock; +static almtx_t ContextSwitchLock; + +static ATOMIC(ALCenum) LastError = ATOMIC_INIT_STATIC(ALC_NO_ERROR); +static PtrIntMap DeviceIfaceMap = PTRINTMAP_STATIC_INITIALIZE; +static PtrIntMap ContextIfaceMap = PTRINTMAP_STATIC_INITIALIZE; + + +typedef struct EnumeratedList { + ALCchar *Names; + ALCchar *NamesEnd; + ALCint *Indicies; + ALCsizei IndexSize; +} EnumeratedList; +static EnumeratedList DevicesList = { NULL, NULL, NULL, 0 }; +static EnumeratedList AllDevicesList = { NULL, NULL, NULL, 0 }; +static EnumeratedList CaptureDevicesList = { NULL, NULL, NULL, 0 }; + +static void ClearDeviceList(EnumeratedList *list) +{ + al_free(list->Names); + list->Names = NULL; + list->NamesEnd = NULL; + + al_free(list->Indicies); + list->Indicies = NULL; + list->IndexSize = 0; +} + +static void AppendDeviceList(EnumeratedList *list, const ALCchar *names, ALint idx) +{ + const ALCchar *name_end = names; + ALCsizei count = 0; + ALCchar *new_list; + ALCint *new_indicies; + size_t len; + ALCsizei i; + + if(!name_end) + return; + while(*name_end) + { + TRACE("Enumerated \"%s\", driver %d\n", name_end, idx); + count++; + name_end += strlen(name_end)+1; + } + if(names == name_end) + return; + + len = (list->NamesEnd - list->Names) + (name_end - names); + new_list = al_calloc(DEF_ALIGN, len + 1); + memcpy(new_list, list->Names, list->NamesEnd - list->Names); + memcpy(new_list + (list->NamesEnd - list->Names), names, name_end - names); + al_free(list->Names); + list->Names = new_list; + list->NamesEnd = list->Names + len; + + new_indicies = al_calloc(16, sizeof(ALCint)*(list->IndexSize + count)); + for(i = 0;i < list->IndexSize;i++) + new_indicies[i] = list->Indicies[i]; + for(i = 0;i < count;i++) + new_indicies[list->IndexSize+i] = idx; + al_free(list->Indicies); + list->Indicies = new_indicies; + list->IndexSize += count; +} + +static ALint GetDriverIndexForName(const EnumeratedList *list, const ALCchar *name) +{ + const ALCchar *devnames = list->Names; + const ALCint *index = list->Indicies; + + while(devnames && *devnames) + { + if(strcmp(name, devnames) == 0) + return *index; + devnames += strlen(devnames)+1; + index++; + } + return -1; +} + +void InitALC(void) +{ + almtx_init(&EnumerationLock, almtx_recursive); + almtx_init(&ContextSwitchLock, almtx_plain); +} + +void ReleaseALC(void) +{ + ClearDeviceList(&DevicesList); + ClearDeviceList(&AllDevicesList); + ClearDeviceList(&CaptureDevicesList); + + ResetPtrIntMap(&ContextIfaceMap); + ResetPtrIntMap(&DeviceIfaceMap); + + almtx_destroy(&ContextSwitchLock); + almtx_destroy(&EnumerationLock); +} + + +ALC_API ALCdevice* ALC_APIENTRY alcOpenDevice(const ALCchar *devicename) +{ + ALCdevice *device = NULL; + ALint idx; + + /* Prior to the enumeration extension, apps would hardcode these names as a + * quality hint for the wrapper driver. Ignore them since there's no sane + * way to map them. + */ + if(devicename && (devicename[0] == '\0' || + strcmp(devicename, "DirectSound3D") == 0 || + strcmp(devicename, "DirectSound") == 0 || + strcmp(devicename, "MMSYSTEM") == 0)) + devicename = NULL; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!DevicesList.Names) + (void)alcGetString(NULL, ALC_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&DevicesList, devicename); + if(idx < 0) + { + if(!AllDevicesList.Names) + (void)alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + idx = GetDriverIndexForName(&AllDevicesList, devicename); + } + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return NULL; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcOpenDevice(devicename); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + { + idx = i; + TRACE("Using default device from driver %d\n", idx); + device = DriverList[idx].alcOpenDevice(NULL); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCloseDevice(device); + device = NULL; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + + +ALC_API ALCcontext* ALC_APIENTRY alcCreateContext(ALCdevice *device, const ALCint *attrlist) +{ + ALCcontext *context; + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + context = DriverList[idx].alcCreateContext(device, attrlist); + if(context) + { + if(InsertPtrIntMapEntry(&ContextIfaceMap, context, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcDestroyContext(context); + context = NULL; + } + } + + return context; +} + +ALC_API ALCboolean ALC_APIENTRY alcMakeContextCurrent(ALCcontext *context) +{ + ALint idx = -1; + + almtx_lock(&ContextSwitchLock); + if(context) + { + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + if(!DriverList[idx].alcMakeContextCurrent(context)) + { + almtx_unlock(&ContextSwitchLock); + return ALC_FALSE; + } + } + + /* Unset the context from the old driver if it's different from the new + * current one. + */ + if(idx < 0) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface) oldiface->alcSetThreadContext(NULL); + oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, NULL); + if(oldiface) oldiface->alcMakeContextCurrent(NULL); + } + else + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcSetThreadContext(NULL); + oldiface = ATOMIC_EXCHANGE_PTR_SEQ(&CurrentCtxDriver, &DriverList[idx]); + if(oldiface && oldiface != &DriverList[idx]) + oldiface->alcMakeContextCurrent(NULL); + } + almtx_unlock(&ContextSwitchLock); + altss_set(ThreadCtxDriver, NULL); + + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcProcessContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcProcessContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcSuspendContext(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcSuspendContext(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); +} + +ALC_API void ALC_APIENTRY alcDestroyContext(ALCcontext *context) +{ + ALint idx; + + if(!context || (idx=LookupPtrIntMapKey(&ContextIfaceMap, context)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return; + } + + DriverList[idx].alcDestroyContext(context); + RemovePtrIntMapKey(&ContextIfaceMap, context); +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetCurrentContext(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(!iface) iface = ATOMIC_LOAD_SEQ(&CurrentCtxDriver); + return iface ? iface->alcGetCurrentContext() : NULL; +} + +ALC_API ALCdevice* ALC_APIENTRY alcGetContextsDevice(ALCcontext *context) +{ + if(context) + { + ALint idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + return DriverList[idx].alcGetContextsDevice(context); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_CONTEXT); + return NULL; +} + + +ALC_API ALCenum ALC_APIENTRY alcGetError(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) return ALC_INVALID_DEVICE; + return DriverList[idx].alcGetError(device); + } + return ATOMIC_EXCHANGE_SEQ(&LastError, ALC_NO_ERROR); +} + +ALC_API ALCboolean ALC_APIENTRY alcIsExtensionPresent(ALCdevice *device, const ALCchar *extname) +{ + const char *ptr; + size_t len; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + return DriverList[idx].alcIsExtensionPresent(device, extname); + } + + len = strlen(extname); + ptr = alcExtensionList; + while(ptr && *ptr) + { + if(strncasecmp(ptr, extname, len) == 0 && (ptr[len] == '\0' || isspace(ptr[len]))) + return ALC_TRUE; + if((ptr=strchr(ptr, ' ')) != NULL) + { + do { + ++ptr; + } while(isspace(*ptr)); + } + } + return ALC_FALSE; +} + +ALC_API void* ALC_APIENTRY alcGetProcAddress(ALCdevice *device, const ALCchar *funcname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return NULL; + } + return DriverList[idx].alcGetProcAddress(device, funcname); + } + + for(i = 0;i < COUNTOF(alcFunctions);i++) + { + if(strcmp(funcname, alcFunctions[i].funcName) == 0) + return alcFunctions[i].address; + } + return NULL; +} + +ALC_API ALCenum ALC_APIENTRY alcGetEnumValue(ALCdevice *device, const ALCchar *enumname) +{ + size_t i; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return 0; + } + return DriverList[idx].alcGetEnumValue(device, enumname); + } + + for(i = 0;i < COUNTOF(alcEnumerations);i++) + { + if(strcmp(enumname, alcEnumerations[i].enumName) == 0) + return alcEnumerations[i].value; + } + return 0; +} + +ALC_API const ALCchar* ALC_APIENTRY alcGetString(ALCdevice *device, ALCenum param) +{ + ALsizei i = 0; + + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return NULL; + } + return DriverList[idx].alcGetString(device, param); + } + + switch(param) + { + case ALC_NO_ERROR: + return alcNoError; + case ALC_INVALID_ENUM: + return alcErrInvalidEnum; + case ALC_INVALID_VALUE: + return alcErrInvalidValue; + case ALC_INVALID_DEVICE: + return alcErrInvalidDevice; + case ALC_INVALID_CONTEXT: + return alcErrInvalidContext; + case ALC_OUT_OF_MEMORY: + return alcErrOutOfMemory; + case ALC_EXTENSIONS: + return alcExtensionList; + + case ALC_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&DevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* Only enumerate names from drivers that support it. */ + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&DevicesList, + DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return DevicesList.Names; + + case ALC_ALL_DEVICES_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&AllDevicesList); + for(i = 0;i < DriverListSize;i++) + { + /* If the driver doesn't support ALC_ENUMERATE_ALL_EXT, substitute + * standard enumeration. + */ + if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER), i + ); + else if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + AppendDeviceList(&AllDevicesList, + DriverList[i].alcGetString(NULL, ALC_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return AllDevicesList.Names; + + case ALC_CAPTURE_DEVICE_SPECIFIER: + almtx_lock(&EnumerationLock); + ClearDeviceList(&CaptureDevicesList); + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + AppendDeviceList(&CaptureDevicesList, + DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER), i + ); + } + almtx_unlock(&EnumerationLock); + return CaptureDevicesList.Names; + + case ALC_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATION_EXT")) + return DriverList[i].alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + case ALC_DEFAULT_ALL_DEVICES_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + return DriverList[i].alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER); + } + return ""; + + case ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER: + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + return DriverList[i].alcGetString(NULL, ALC_CAPTURE_DEFAULT_DEVICE_SPECIFIER); + } + return ""; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + break; + } + return NULL; +} + +ALC_API void ALC_APIENTRY alcGetIntegerv(ALCdevice *device, ALCenum param, ALCsizei size, ALCint *values) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + } + return DriverList[idx].alcGetIntegerv(device, param, size, values); + } + + if(size <= 0 || values == NULL) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + } + + switch(param) + { + case ALC_MAJOR_VERSION: + if(size >= 1) + { + values[0] = alcMajorVersion; + return; + } + /*fall-through*/ + case ALC_MINOR_VERSION: + if(size >= 1) + { + values[0] = alcMinorVersion; + return; + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + return; + + case ALC_ATTRIBUTES_SIZE: + case ALC_ALL_ATTRIBUTES: + case ALC_FREQUENCY: + case ALC_REFRESH: + case ALC_SYNC: + case ALC_MONO_SOURCES: + case ALC_STEREO_SOURCES: + case ALC_CAPTURE_SAMPLES: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return; + + default: + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_ENUM); + return; + } +} + + +ALC_API ALCdevice* ALC_APIENTRY alcCaptureOpenDevice(const ALCchar *devicename, ALCuint frequency, ALCenum format, ALCsizei buffersize) +{ + ALCdevice *device = NULL; + ALint idx; + + if(devicename && devicename[0] == '\0') + devicename = NULL; + if(devicename) + { + almtx_lock(&EnumerationLock); + if(!CaptureDevicesList.Names) + (void)alcGetString(NULL, ALC_CAPTURE_DEVICE_SPECIFIER); + idx = GetDriverIndexForName(&CaptureDevicesList, devicename); + almtx_unlock(&EnumerationLock); + if(idx < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_VALUE); + TRACE("Failed to find driver for name \"%s\"\n", devicename); + return NULL; + } + TRACE("Found driver %d for name \"%s\"\n", idx, devicename); + device = DriverList[idx].alcCaptureOpenDevice( + devicename, frequency, format, buffersize + ); + } + else + { + int i; + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].ALCVer >= MAKE_ALC_VER(1, 1) || + DriverList[i].alcIsExtensionPresent(NULL, "ALC_EXT_CAPTURE")) + { + idx = i; + TRACE("Using default capture device from driver %d\n", idx); + device = DriverList[idx].alcCaptureOpenDevice( + NULL, frequency, format, buffersize + ); + break; + } + } + } + + if(device) + { + if(InsertPtrIntMapEntry(&DeviceIfaceMap, device, idx) != ALC_NO_ERROR) + { + DriverList[idx].alcCaptureCloseDevice(device); + device = NULL; + } + } + + return device; +} + +ALC_API ALCboolean ALC_APIENTRY alcCaptureCloseDevice(ALCdevice *device) +{ + ALint idx; + + if(!device || (idx=LookupPtrIntMapKey(&DeviceIfaceMap, device)) < 0) + { + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); + return ALC_FALSE; + } + if(!DriverList[idx].alcCaptureCloseDevice(device)) + return ALC_FALSE; + RemovePtrIntMapKey(&DeviceIfaceMap, device); + return ALC_TRUE; +} + +ALC_API void ALC_APIENTRY alcCaptureStart(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStart(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureStop(ALCdevice *device) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureStop(device); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + +ALC_API void ALC_APIENTRY alcCaptureSamples(ALCdevice *device, ALCvoid *buffer, ALCsizei samples) +{ + if(device) + { + ALint idx = LookupPtrIntMapKey(&DeviceIfaceMap, device); + if(idx >= 0) + return DriverList[idx].alcCaptureSamples(device, buffer, samples); + } + ATOMIC_STORE_SEQ(&LastError, ALC_INVALID_DEVICE); +} + + +ALC_API ALCboolean ALC_APIENTRY alcSetThreadContext(ALCcontext *context) +{ + ALCenum err = ALC_INVALID_CONTEXT; + ALint idx; + + if(!context) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface && !oldiface->alcSetThreadContext(NULL)) + return ALC_FALSE; + altss_set(ThreadCtxDriver, NULL); + return ALC_TRUE; + } + + idx = LookupPtrIntMapKey(&ContextIfaceMap, context); + if(idx >= 0) + { + if(DriverList[idx].alcSetThreadContext(context)) + { + DriverIface *oldiface = altss_get(ThreadCtxDriver); + if(oldiface != &DriverList[idx]) + { + altss_set(ThreadCtxDriver, &DriverList[idx]); + if(oldiface) oldiface->alcSetThreadContext(NULL); + } + return ALC_TRUE; + } + err = DriverList[idx].alcGetError(NULL); + } + ATOMIC_STORE_SEQ(&LastError, err); + return ALC_FALSE; +} + +ALC_API ALCcontext* ALC_APIENTRY alcGetThreadContext(void) +{ + DriverIface *iface = altss_get(ThreadCtxDriver); + if(iface) return iface->alcGetThreadContext(); + return NULL; +} diff --git a/router/router.c b/router/router.c new file mode 100644 index 00000000..bff73776 --- /dev/null +++ b/router/router.c @@ -0,0 +1,537 @@ + +#include "config.h" + +#include "router.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "AL/alc.h" +#include "AL/al.h" +#include "almalloc.h" + +#include "version.h" + + +DriverIface *DriverList = NULL; +int DriverListSize = 0; +static int DriverListSizeMax = 0; + +altss_t ThreadCtxDriver; + +enum LogLevel LogLevel = LogLevel_Error; +FILE *LogFile; + +static void LoadDriverList(void); + + +BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved)) +{ + const char *str; + int i; + + switch(reason) + { + case DLL_PROCESS_ATTACH: + LogFile = stderr; + str = getenv("ALROUTER_LOGFILE"); + if(str && *str != '\0') + { + FILE *f = fopen(str, "w"); + if(f == NULL) + ERR("Could not open log file: %s\n", str); + else + LogFile = f; + } + str = getenv("ALROUTER_LOGLEVEL"); + if(str && *str != '\0') + { + char *end = NULL; + long l = strtol(str, &end, 0); + if(!end || *end != '\0') + ERR("Invalid log level value: %s\n", str); + else if(l < LogLevel_None || l > LogLevel_Trace) + ERR("Log level out of range: %s\n", str); + else + LogLevel = l; + } + TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH); + LoadDriverList(); + + altss_create(&ThreadCtxDriver, NULL); + InitALC(); + break; + + case DLL_THREAD_ATTACH: + break; + case DLL_THREAD_DETACH: + althrd_thread_detach(); + break; + + case DLL_PROCESS_DETACH: + ReleaseALC(); + altss_delete(ThreadCtxDriver); + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module) + FreeLibrary(DriverList[i].Module); + } + al_free(DriverList); + DriverList = NULL; + DriverListSize = 0; + DriverListSizeMax = 0; + + if(LogFile && LogFile != stderr) + fclose(LogFile); + LogFile = NULL; + + althrd_deinit(); + break; + } + return TRUE; +} + + +#ifdef __GNUC__ +#define CAST_FUNC(x) (__typeof(x)) +#else +#define CAST_FUNC(x) (void*) +#endif + +static void AddModule(HMODULE module, const WCHAR *name) +{ + DriverIface newdrv; + int err = 0; + int i; + + for(i = 0;i < DriverListSize;i++) + { + if(DriverList[i].Module == module) + { + TRACE("Skipping already-loaded module %p\n", module); + FreeLibrary(module); + return; + } + if(wcscmp(DriverList[i].Name, name) == 0) + { + TRACE("Skipping similarly-named module %ls\n", name); + FreeLibrary(module); + return; + } + } + + if(DriverListSize == DriverListSizeMax) + { + int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4; + void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax); + if(!newlist) return; + + memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0])); + al_free(DriverList); + DriverList = newlist; + DriverListSizeMax = newmax; + } + + memset(&newdrv, 0, sizeof(newdrv)); + /* Load required functions. */ +#define LOAD_PROC(x) do { \ + newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + LOAD_PROC(alcCreateContext); + LOAD_PROC(alcMakeContextCurrent); + LOAD_PROC(alcProcessContext); + LOAD_PROC(alcSuspendContext); + LOAD_PROC(alcDestroyContext); + LOAD_PROC(alcGetCurrentContext); + LOAD_PROC(alcGetContextsDevice); + LOAD_PROC(alcOpenDevice); + LOAD_PROC(alcCloseDevice); + LOAD_PROC(alcGetError); + LOAD_PROC(alcIsExtensionPresent); + LOAD_PROC(alcGetProcAddress); + LOAD_PROC(alcGetEnumValue); + LOAD_PROC(alcGetString); + LOAD_PROC(alcGetIntegerv); + LOAD_PROC(alcCaptureOpenDevice); + LOAD_PROC(alcCaptureCloseDevice); + LOAD_PROC(alcCaptureStart); + LOAD_PROC(alcCaptureStop); + LOAD_PROC(alcCaptureSamples); + + LOAD_PROC(alEnable); + LOAD_PROC(alDisable); + LOAD_PROC(alIsEnabled); + LOAD_PROC(alGetString); + LOAD_PROC(alGetBooleanv); + LOAD_PROC(alGetIntegerv); + LOAD_PROC(alGetFloatv); + LOAD_PROC(alGetDoublev); + LOAD_PROC(alGetBoolean); + LOAD_PROC(alGetInteger); + LOAD_PROC(alGetFloat); + LOAD_PROC(alGetDouble); + LOAD_PROC(alGetError); + LOAD_PROC(alIsExtensionPresent); + LOAD_PROC(alGetProcAddress); + LOAD_PROC(alGetEnumValue); + LOAD_PROC(alListenerf); + LOAD_PROC(alListener3f); + LOAD_PROC(alListenerfv); + LOAD_PROC(alListeneri); + LOAD_PROC(alListener3i); + LOAD_PROC(alListeneriv); + LOAD_PROC(alGetListenerf); + LOAD_PROC(alGetListener3f); + LOAD_PROC(alGetListenerfv); + LOAD_PROC(alGetListeneri); + LOAD_PROC(alGetListener3i); + LOAD_PROC(alGetListeneriv); + LOAD_PROC(alGenSources); + LOAD_PROC(alDeleteSources); + LOAD_PROC(alIsSource); + LOAD_PROC(alSourcef); + LOAD_PROC(alSource3f); + LOAD_PROC(alSourcefv); + LOAD_PROC(alSourcei); + LOAD_PROC(alSource3i); + LOAD_PROC(alSourceiv); + LOAD_PROC(alGetSourcef); + LOAD_PROC(alGetSource3f); + LOAD_PROC(alGetSourcefv); + LOAD_PROC(alGetSourcei); + LOAD_PROC(alGetSource3i); + LOAD_PROC(alGetSourceiv); + LOAD_PROC(alSourcePlayv); + LOAD_PROC(alSourceStopv); + LOAD_PROC(alSourceRewindv); + LOAD_PROC(alSourcePausev); + LOAD_PROC(alSourcePlay); + LOAD_PROC(alSourceStop); + LOAD_PROC(alSourceRewind); + LOAD_PROC(alSourcePause); + LOAD_PROC(alSourceQueueBuffers); + LOAD_PROC(alSourceUnqueueBuffers); + LOAD_PROC(alGenBuffers); + LOAD_PROC(alDeleteBuffers); + LOAD_PROC(alIsBuffer); + LOAD_PROC(alBufferf); + LOAD_PROC(alBuffer3f); + LOAD_PROC(alBufferfv); + LOAD_PROC(alBufferi); + LOAD_PROC(alBuffer3i); + LOAD_PROC(alBufferiv); + LOAD_PROC(alGetBufferf); + LOAD_PROC(alGetBuffer3f); + LOAD_PROC(alGetBufferfv); + LOAD_PROC(alGetBufferi); + LOAD_PROC(alGetBuffer3i); + LOAD_PROC(alGetBufferiv); + LOAD_PROC(alBufferData); + LOAD_PROC(alDopplerFactor); + LOAD_PROC(alDopplerVelocity); + LOAD_PROC(alSpeedOfSound); + LOAD_PROC(alDistanceModel); + if(!err) + { + ALCint alc_ver[2] = { 0, 0 }; + wcsncpy(newdrv.Name, name, 32); + newdrv.Module = module; + newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]); + newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]); + if(newdrv.alcGetError(NULL) == ALC_NO_ERROR) + newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]); + else + newdrv.ALCVer = MAKE_ALC_VER(1, 0); + +#undef LOAD_PROC +#define LOAD_PROC(x) do { \ + newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \ + if(!newdrv.x) \ + { \ + ERR("Failed to find entry point for %s in %ls\n", #x, name); \ + err = 1; \ + } \ +} while(0) + if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context")) + { + LOAD_PROC(alcSetThreadContext); + LOAD_PROC(alcGetThreadContext); + } + } + + if(!err) + { + TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, + newdrv.ALCVer>>8, newdrv.ALCVer&255); + DriverList[DriverListSize++] = newdrv; + } +#undef LOAD_PROC +} + +static void SearchDrivers(WCHAR *path) +{ + WCHAR srchPath[MAX_PATH+1] = L""; + WIN32_FIND_DATAW fdata; + HANDLE srchHdl; + + TRACE("Searching for drivers in %ls...\n", path); + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath)); + srchHdl = FindFirstFileW(srchPath, &fdata); + if(srchHdl != INVALID_HANDLE_VALUE) + { + do { + HMODULE mod; + + wcsncpy(srchPath, path, MAX_PATH); + wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath)); + wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath)); + TRACE("Found %ls\n", srchPath); + + mod = LoadLibraryW(srchPath); + if(!mod) + WARN("Could not load %ls\n", srchPath); + else + AddModule(mod, fdata.cFileName); + } while(FindNextFileW(srchHdl, &fdata)); + FindClose(srchHdl); + } +} + +static WCHAR *strrchrW(WCHAR *str, WCHAR ch) +{ + WCHAR *res = NULL; + while(str && *str != '\0') + { + if(*str == ch) + res = str; + ++str; + } + return res; +} + +static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length) +{ + HMODULE module = NULL; + WCHAR *sep0, *sep1; + + if(name) + { + module = GetModuleHandleW(name); + if(!module) return 0; + } + + if(GetModuleFileNameW(module, moddir, length) == 0) + return 0; + + sep0 = strrchrW(moddir, '/'); + if(sep0) sep1 = strrchrW(sep0+1, '\\'); + else sep1 = strrchrW(moddir, '\\'); + + if(sep1) *sep1 = '\0'; + else if(sep0) *sep0 = '\0'; + else *moddir = '\0'; + + return 1; +} + +void LoadDriverList(void) +{ + WCHAR dll_path[MAX_PATH+1] = L""; + WCHAR cwd_path[MAX_PATH+1] = L""; + WCHAR proc_path[MAX_PATH+1] = L""; + WCHAR sys_path[MAX_PATH+1] = L""; + int len; + + if(GetLoadedModuleDirectory(L"OpenAL32.dll", dll_path, MAX_PATH)) + TRACE("Got DLL path %ls\n", dll_path); + + GetCurrentDirectoryW(MAX_PATH, cwd_path); + len = lstrlenW(cwd_path); + if(len > 0 && (cwd_path[len-1] == '\\' || cwd_path[len-1] == '/')) + cwd_path[len-1] = '\0'; + TRACE("Got current working directory %ls\n", cwd_path); + + if(GetLoadedModuleDirectory(NULL, proc_path, MAX_PATH)) + TRACE("Got proc path %ls\n", proc_path); + + GetSystemDirectoryW(sys_path, MAX_PATH); + len = lstrlenW(sys_path); + if(len > 0 && (sys_path[len-1] == '\\' || sys_path[len-1] == '/')) + sys_path[len-1] = '\0'; + TRACE("Got system path %ls\n", sys_path); + + /* Don't search the DLL's path if it is the same as the current working + * directory, app's path, or system path (don't want to do duplicate + * searches, or increase the priority of the app or system path). + */ + if(dll_path[0] && + (!cwd_path[0] || wcscmp(dll_path, cwd_path) != 0) && + (!proc_path[0] || wcscmp(dll_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(dll_path, sys_path) != 0)) + SearchDrivers(dll_path); + if(cwd_path[0] && + (!proc_path[0] || wcscmp(cwd_path, proc_path) != 0) && + (!sys_path[0] || wcscmp(cwd_path, sys_path) != 0)) + SearchDrivers(cwd_path); + if(proc_path[0] && (!sys_path[0] || wcscmp(proc_path, sys_path) != 0)) + SearchDrivers(proc_path); + if(sys_path[0]) + SearchDrivers(sys_path); +} + + +void InitPtrIntMap(PtrIntMap *map) +{ + map->keys = NULL; + map->values = NULL; + map->size = 0; + map->capacity = 0; + RWLockInit(&map->lock); +} + +void ResetPtrIntMap(PtrIntMap *map) +{ + WriteLock(&map->lock); + al_free(map->keys); + map->keys = NULL; + map->values = NULL; + map->size = 0; + map->capacity = 0; + WriteUnlock(&map->lock); +} + +ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value) +{ + ALsizei pos = 0; + + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + } + + if(pos == map->size || map->keys[pos] != key) + { + if(map->size == map->capacity) + { + ALvoid **keys = NULL; + ALint *values; + ALsizei newcap; + + newcap = (map->capacity ? (map->capacity<<1) : 4); + if(newcap > map->capacity) + keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap); + if(!keys) + { + WriteUnlock(&map->lock); + return AL_OUT_OF_MEMORY; + } + values = (ALint*)&keys[newcap]; + + if(map->keys) + { + memcpy(keys, map->keys, map->size*sizeof(map->keys[0])); + memcpy(values, map->values, map->size*sizeof(map->values[0])); + } + al_free(map->keys); + map->keys = keys; + map->values = values; + map->capacity = newcap; + } + + if(pos < map->size) + { + memmove(&map->keys[pos+1], &map->keys[pos], + (map->size-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos+1], &map->values[pos], + (map->size-pos)*sizeof(map->values[0])); + } + map->size++; + } + map->keys[pos] = key; + map->values[pos] = value; + WriteUnlock(&map->lock); + + return AL_NO_ERROR; +} + +ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + WriteLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + { + ret = map->values[pos]; + if(pos < map->size-1) + { + memmove(&map->keys[pos], &map->keys[pos+1], + (map->size-1-pos)*sizeof(map->keys[0])); + memmove(&map->values[pos], &map->values[pos+1], + (map->size-1-pos)*sizeof(map->values[0])); + } + map->size--; + } + } + WriteUnlock(&map->lock); + return ret; +} + +ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key) +{ + ALint ret = -1; + ReadLock(&map->lock); + if(map->size > 0) + { + ALsizei pos = 0; + ALsizei count = map->size; + do { + ALsizei step = count>>1; + ALsizei i = pos+step; + if(!(map->keys[i] < key)) + count = step; + else + { + pos = i+1; + count -= step+1; + } + } while(count > 0); + if(pos < map->size && map->keys[pos] == key) + ret = map->values[pos]; + } + ReadUnlock(&map->lock); + return ret; +} diff --git a/router/router.h b/router/router.h new file mode 100644 index 00000000..32a91dcb --- /dev/null +++ b/router/router.h @@ -0,0 +1,197 @@ +#ifndef ROUTER_ROUTER_H +#define ROUTER_ROUTER_H + +#define WIN32_LEAN_AND_MEAN +#include <windows.h> +#include <winnt.h> + +#include <stdio.h> + +#include "AL/alc.h" +#include "AL/al.h" +#include "AL/alext.h" +#include "atomic.h" +#include "rwlock.h" +#include "threads.h" + + +#ifndef UNUSED +#if defined(__cplusplus) +#define UNUSED(x) +#elif defined(__GNUC__) +#define UNUSED(x) UNUSED_##x __attribute__((unused)) +#elif defined(__LCLINT__) +#define UNUSED(x) /*@unused@*/ x +#else +#define UNUSED(x) x +#endif +#endif + +#define MAKE_ALC_VER(major, minor) (((major)<<8) | (minor)) + +typedef struct DriverIface { + WCHAR Name[32]; + HMODULE Module; + int ALCVer; + + LPALCCREATECONTEXT alcCreateContext; + LPALCMAKECONTEXTCURRENT alcMakeContextCurrent; + LPALCPROCESSCONTEXT alcProcessContext; + LPALCSUSPENDCONTEXT alcSuspendContext; + LPALCDESTROYCONTEXT alcDestroyContext; + LPALCGETCURRENTCONTEXT alcGetCurrentContext; + LPALCGETCONTEXTSDEVICE alcGetContextsDevice; + LPALCOPENDEVICE alcOpenDevice; + LPALCCLOSEDEVICE alcCloseDevice; + LPALCGETERROR alcGetError; + LPALCISEXTENSIONPRESENT alcIsExtensionPresent; + LPALCGETPROCADDRESS alcGetProcAddress; + LPALCGETENUMVALUE alcGetEnumValue; + LPALCGETSTRING alcGetString; + LPALCGETINTEGERV alcGetIntegerv; + LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice; + LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice; + LPALCCAPTURESTART alcCaptureStart; + LPALCCAPTURESTOP alcCaptureStop; + LPALCCAPTURESAMPLES alcCaptureSamples; + + PFNALCSETTHREADCONTEXTPROC alcSetThreadContext; + PFNALCGETTHREADCONTEXTPROC alcGetThreadContext; + + LPALENABLE alEnable; + LPALDISABLE alDisable; + LPALISENABLED alIsEnabled; + LPALGETSTRING alGetString; + LPALGETBOOLEANV alGetBooleanv; + LPALGETINTEGERV alGetIntegerv; + LPALGETFLOATV alGetFloatv; + LPALGETDOUBLEV alGetDoublev; + LPALGETBOOLEAN alGetBoolean; + LPALGETINTEGER alGetInteger; + LPALGETFLOAT alGetFloat; + LPALGETDOUBLE alGetDouble; + LPALGETERROR alGetError; + LPALISEXTENSIONPRESENT alIsExtensionPresent; + LPALGETPROCADDRESS alGetProcAddress; + LPALGETENUMVALUE alGetEnumValue; + LPALLISTENERF alListenerf; + LPALLISTENER3F alListener3f; + LPALLISTENERFV alListenerfv; + LPALLISTENERI alListeneri; + LPALLISTENER3I alListener3i; + LPALLISTENERIV alListeneriv; + LPALGETLISTENERF alGetListenerf; + LPALGETLISTENER3F alGetListener3f; + LPALGETLISTENERFV alGetListenerfv; + LPALGETLISTENERI alGetListeneri; + LPALGETLISTENER3I alGetListener3i; + LPALGETLISTENERIV alGetListeneriv; + LPALGENSOURCES alGenSources; + LPALDELETESOURCES alDeleteSources; + LPALISSOURCE alIsSource; + LPALSOURCEF alSourcef; + LPALSOURCE3F alSource3f; + LPALSOURCEFV alSourcefv; + LPALSOURCEI alSourcei; + LPALSOURCE3I alSource3i; + LPALSOURCEIV alSourceiv; + LPALGETSOURCEF alGetSourcef; + LPALGETSOURCE3F alGetSource3f; + LPALGETSOURCEFV alGetSourcefv; + LPALGETSOURCEI alGetSourcei; + LPALGETSOURCE3I alGetSource3i; + LPALGETSOURCEIV alGetSourceiv; + LPALSOURCEPLAYV alSourcePlayv; + LPALSOURCESTOPV alSourceStopv; + LPALSOURCEREWINDV alSourceRewindv; + LPALSOURCEPAUSEV alSourcePausev; + LPALSOURCEPLAY alSourcePlay; + LPALSOURCESTOP alSourceStop; + LPALSOURCEREWIND alSourceRewind; + LPALSOURCEPAUSE alSourcePause; + LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers; + LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers; + LPALGENBUFFERS alGenBuffers; + LPALDELETEBUFFERS alDeleteBuffers; + LPALISBUFFER alIsBuffer; + LPALBUFFERF alBufferf; + LPALBUFFER3F alBuffer3f; + LPALBUFFERFV alBufferfv; + LPALBUFFERI alBufferi; + LPALBUFFER3I alBuffer3i; + LPALBUFFERIV alBufferiv; + LPALGETBUFFERF alGetBufferf; + LPALGETBUFFER3F alGetBuffer3f; + LPALGETBUFFERFV alGetBufferfv; + LPALGETBUFFERI alGetBufferi; + LPALGETBUFFER3I alGetBuffer3i; + LPALGETBUFFERIV alGetBufferiv; + LPALBUFFERDATA alBufferData; + LPALDOPPLERFACTOR alDopplerFactor; + LPALDOPPLERVELOCITY alDopplerVelocity; + LPALSPEEDOFSOUND alSpeedOfSound; + LPALDISTANCEMODEL alDistanceModel; +} DriverIface; + +extern DriverIface *DriverList; +extern int DriverListSize; + +extern altss_t ThreadCtxDriver; +typedef ATOMIC(DriverIface*) atomic_DriverIfacePtr; +extern atomic_DriverIfacePtr CurrentCtxDriver; + + +typedef struct PtrIntMap { + ALvoid **keys; + /* Shares memory with keys. */ + ALint *values; + + ALsizei size; + ALsizei capacity; + RWLock lock; +} PtrIntMap; +#define PTRINTMAP_STATIC_INITIALIZE { NULL, NULL, 0, 0, RWLOCK_STATIC_INITIALIZE } + +void InitPtrIntMap(PtrIntMap *map); +void ResetPtrIntMap(PtrIntMap *map); +ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value); +ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key); +ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key); + + +void InitALC(void); +void ReleaseALC(void); + + +enum LogLevel { + LogLevel_None = 0, + LogLevel_Error = 1, + LogLevel_Warn = 2, + LogLevel_Trace = 3, +}; +extern enum LogLevel LogLevel; +extern FILE *LogFile; + +#define TRACE(...) do { \ + if(LogLevel >= LogLevel_Trace) \ + { \ + fprintf(LogFile, "AL Router (II): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) +#define WARN(...) do { \ + if(LogLevel >= LogLevel_Warn) \ + { \ + fprintf(LogFile, "AL Router (WW): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) +#define ERR(...) do { \ + if(LogLevel >= LogLevel_Error) \ + { \ + fprintf(LogFile, "AL Router (EE): " __VA_ARGS__); \ + fflush(LogFile); \ + } \ +} while(0) + +#endif /* ROUTER_ROUTER_H */ |