mirror of
https://github.com/etlegacy/etlegacy-libs.git
synced 2024-11-10 14:51:58 +00:00
513 lines
14 KiB
C
513 lines
14 KiB
C
|
|
||
|
#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:
|
||
|
case DLL_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;
|
||
|
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 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;
|
||
|
}
|