#include "config.h" #include "router.h" #include #include #include #include "AL/alc.h" #include "AL/al.h" #include "almalloc.h" DriverIface *DriverList = NULL; int DriverListSize = 0; static int DriverListSizeMax = 0; almtx_t EnumerationLock; almtx_t ContextSwitchLock; 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; } LoadDriverList(); almtx_init(&EnumerationLock, almtx_recursive); almtx_init(&ContextSwitchLock, almtx_plain); break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; case DLL_PROCESS_DETACH: ReleaseALC(); almtx_destroy(&ContextSwitchLock); almtx_destroy(&EnumerationLock); 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; 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)); #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); TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name, newdrv.ALCVer>>8, newdrv.ALCVer&255); DriverList[DriverListSize++] = newdrv; } } 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 path[MAX_PATH+1] = L""; int len; if(GetLoadedModuleDirectory(L"OpenAL32.dll", path, MAX_PATH)) SearchDrivers(path); GetCurrentDirectoryW(MAX_PATH, path); len = lstrlenW(path); if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) path[len-1] = '\0'; SearchDrivers(path); if(GetLoadedModuleDirectory(NULL, path, MAX_PATH)) SearchDrivers(path); GetSystemDirectoryW(path, MAX_PATH); len = lstrlenW(path); if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/')) path[len-1] = '\0'; SearchDrivers(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; }