Restore the original JACK message callback when possible
[openal-soft.git] / router / router.c
blob0497a1d2811f9c91cc167318a294915b24202f4a
2 #include "config.h"
4 #include "router.h"
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
10 #include "AL/alc.h"
11 #include "AL/al.h"
12 #include "almalloc.h"
14 #include "version.h"
17 DriverIface *DriverList = NULL;
18 int DriverListSize = 0;
19 static int DriverListSizeMax = 0;
21 altss_t ThreadCtxDriver;
23 enum LogLevel LogLevel = LogLevel_Error;
24 FILE *LogFile;
26 static void LoadDriverList(void);
29 BOOL APIENTRY DllMain(HINSTANCE UNUSED(module), DWORD reason, void* UNUSED(reserved))
31 const char *str;
32 int i;
34 switch(reason)
36 case DLL_PROCESS_ATTACH:
37 LogFile = stderr;
38 str = getenv("ALROUTER_LOGFILE");
39 if(str && *str != '\0')
41 FILE *f = fopen(str, "w");
42 if(f == NULL)
43 ERR("Could not open log file: %s\n", str);
44 else
45 LogFile = f;
47 str = getenv("ALROUTER_LOGLEVEL");
48 if(str && *str != '\0')
50 char *end = NULL;
51 long l = strtol(str, &end, 0);
52 if(!end || *end != '\0')
53 ERR("Invalid log level value: %s\n", str);
54 else if(l < LogLevel_None || l > LogLevel_Trace)
55 ERR("Log level out of range: %s\n", str);
56 else
57 LogLevel = l;
59 TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH);
60 LoadDriverList();
62 altss_create(&ThreadCtxDriver, NULL);
63 InitALC();
64 break;
66 case DLL_THREAD_ATTACH:
67 case DLL_THREAD_DETACH:
68 break;
70 case DLL_PROCESS_DETACH:
71 ReleaseALC();
72 altss_delete(ThreadCtxDriver);
74 for(i = 0;i < DriverListSize;i++)
76 if(DriverList[i].Module)
77 FreeLibrary(DriverList[i].Module);
79 al_free(DriverList);
80 DriverList = NULL;
81 DriverListSize = 0;
82 DriverListSizeMax = 0;
84 if(LogFile && LogFile != stderr)
85 fclose(LogFile);
86 LogFile = NULL;
87 break;
89 return TRUE;
93 #ifdef __GNUC__
94 #define CAST_FUNC(x) (__typeof(x))
95 #else
96 #define CAST_FUNC(x) (void*)
97 #endif
99 static void AddModule(HMODULE module, const WCHAR *name)
101 DriverIface newdrv;
102 int err = 0;
103 int i;
105 for(i = 0;i < DriverListSize;i++)
107 if(DriverList[i].Module == module)
109 TRACE("Skipping already-loaded module %p\n", module);
110 FreeLibrary(module);
111 return;
113 if(wcscmp(DriverList[i].Name, name) == 0)
115 TRACE("Skipping similarly-named module %ls\n", name);
116 FreeLibrary(module);
117 return;
121 if(DriverListSize == DriverListSizeMax)
123 int newmax = DriverListSizeMax ? DriverListSizeMax<<1 : 4;
124 void *newlist = al_calloc(DEF_ALIGN, sizeof(DriverList[0])*newmax);
125 if(!newlist) return;
127 memcpy(newlist, DriverList, DriverListSize*sizeof(DriverList[0]));
128 al_free(DriverList);
129 DriverList = newlist;
130 DriverListSizeMax = newmax;
133 memset(&newdrv, 0, sizeof(newdrv));
134 /* Load required functions. */
135 #define LOAD_PROC(x) do { \
136 newdrv.x = CAST_FUNC(newdrv.x) GetProcAddress(module, #x); \
137 if(!newdrv.x) \
139 ERR("Failed to find entry point for %s in %ls\n", #x, name); \
140 err = 1; \
142 } while(0)
143 LOAD_PROC(alcCreateContext);
144 LOAD_PROC(alcMakeContextCurrent);
145 LOAD_PROC(alcProcessContext);
146 LOAD_PROC(alcSuspendContext);
147 LOAD_PROC(alcDestroyContext);
148 LOAD_PROC(alcGetCurrentContext);
149 LOAD_PROC(alcGetContextsDevice);
150 LOAD_PROC(alcOpenDevice);
151 LOAD_PROC(alcCloseDevice);
152 LOAD_PROC(alcGetError);
153 LOAD_PROC(alcIsExtensionPresent);
154 LOAD_PROC(alcGetProcAddress);
155 LOAD_PROC(alcGetEnumValue);
156 LOAD_PROC(alcGetString);
157 LOAD_PROC(alcGetIntegerv);
158 LOAD_PROC(alcCaptureOpenDevice);
159 LOAD_PROC(alcCaptureCloseDevice);
160 LOAD_PROC(alcCaptureStart);
161 LOAD_PROC(alcCaptureStop);
162 LOAD_PROC(alcCaptureSamples);
164 LOAD_PROC(alEnable);
165 LOAD_PROC(alDisable);
166 LOAD_PROC(alIsEnabled);
167 LOAD_PROC(alGetString);
168 LOAD_PROC(alGetBooleanv);
169 LOAD_PROC(alGetIntegerv);
170 LOAD_PROC(alGetFloatv);
171 LOAD_PROC(alGetDoublev);
172 LOAD_PROC(alGetBoolean);
173 LOAD_PROC(alGetInteger);
174 LOAD_PROC(alGetFloat);
175 LOAD_PROC(alGetDouble);
176 LOAD_PROC(alGetError);
177 LOAD_PROC(alIsExtensionPresent);
178 LOAD_PROC(alGetProcAddress);
179 LOAD_PROC(alGetEnumValue);
180 LOAD_PROC(alListenerf);
181 LOAD_PROC(alListener3f);
182 LOAD_PROC(alListenerfv);
183 LOAD_PROC(alListeneri);
184 LOAD_PROC(alListener3i);
185 LOAD_PROC(alListeneriv);
186 LOAD_PROC(alGetListenerf);
187 LOAD_PROC(alGetListener3f);
188 LOAD_PROC(alGetListenerfv);
189 LOAD_PROC(alGetListeneri);
190 LOAD_PROC(alGetListener3i);
191 LOAD_PROC(alGetListeneriv);
192 LOAD_PROC(alGenSources);
193 LOAD_PROC(alDeleteSources);
194 LOAD_PROC(alIsSource);
195 LOAD_PROC(alSourcef);
196 LOAD_PROC(alSource3f);
197 LOAD_PROC(alSourcefv);
198 LOAD_PROC(alSourcei);
199 LOAD_PROC(alSource3i);
200 LOAD_PROC(alSourceiv);
201 LOAD_PROC(alGetSourcef);
202 LOAD_PROC(alGetSource3f);
203 LOAD_PROC(alGetSourcefv);
204 LOAD_PROC(alGetSourcei);
205 LOAD_PROC(alGetSource3i);
206 LOAD_PROC(alGetSourceiv);
207 LOAD_PROC(alSourcePlayv);
208 LOAD_PROC(alSourceStopv);
209 LOAD_PROC(alSourceRewindv);
210 LOAD_PROC(alSourcePausev);
211 LOAD_PROC(alSourcePlay);
212 LOAD_PROC(alSourceStop);
213 LOAD_PROC(alSourceRewind);
214 LOAD_PROC(alSourcePause);
215 LOAD_PROC(alSourceQueueBuffers);
216 LOAD_PROC(alSourceUnqueueBuffers);
217 LOAD_PROC(alGenBuffers);
218 LOAD_PROC(alDeleteBuffers);
219 LOAD_PROC(alIsBuffer);
220 LOAD_PROC(alBufferf);
221 LOAD_PROC(alBuffer3f);
222 LOAD_PROC(alBufferfv);
223 LOAD_PROC(alBufferi);
224 LOAD_PROC(alBuffer3i);
225 LOAD_PROC(alBufferiv);
226 LOAD_PROC(alGetBufferf);
227 LOAD_PROC(alGetBuffer3f);
228 LOAD_PROC(alGetBufferfv);
229 LOAD_PROC(alGetBufferi);
230 LOAD_PROC(alGetBuffer3i);
231 LOAD_PROC(alGetBufferiv);
232 LOAD_PROC(alBufferData);
233 LOAD_PROC(alDopplerFactor);
234 LOAD_PROC(alDopplerVelocity);
235 LOAD_PROC(alSpeedOfSound);
236 LOAD_PROC(alDistanceModel);
237 if(!err)
239 ALCint alc_ver[2] = { 0, 0 };
240 wcsncpy(newdrv.Name, name, 32);
241 newdrv.Module = module;
242 newdrv.alcGetIntegerv(NULL, ALC_MAJOR_VERSION, 1, &alc_ver[0]);
243 newdrv.alcGetIntegerv(NULL, ALC_MINOR_VERSION, 1, &alc_ver[1]);
244 if(newdrv.alcGetError(NULL) == ALC_NO_ERROR)
245 newdrv.ALCVer = MAKE_ALC_VER(alc_ver[0], alc_ver[1]);
246 else
247 newdrv.ALCVer = MAKE_ALC_VER(1, 0);
249 #undef LOAD_PROC
250 #define LOAD_PROC(x) do { \
251 newdrv.x = CAST_FUNC(newdrv.x) newdrv.alcGetProcAddress(NULL, #x); \
252 if(!newdrv.x) \
254 ERR("Failed to find entry point for %s in %ls\n", #x, name); \
255 err = 1; \
257 } while(0)
258 if(newdrv.alcIsExtensionPresent(NULL, "ALC_EXT_thread_local_context"))
260 LOAD_PROC(alcSetThreadContext);
261 LOAD_PROC(alcGetThreadContext);
265 if(!err)
267 TRACE("Loaded module %p, %ls, ALC %d.%d\n", module, name,
268 newdrv.ALCVer>>8, newdrv.ALCVer&255);
269 DriverList[DriverListSize++] = newdrv;
271 #undef LOAD_PROC
274 static void SearchDrivers(WCHAR *path)
276 WCHAR srchPath[MAX_PATH+1] = L"";
277 WIN32_FIND_DATAW fdata;
278 HANDLE srchHdl;
280 TRACE("Searching for drivers in %ls...\n", path);
281 wcsncpy(srchPath, path, MAX_PATH);
282 wcsncat(srchPath, L"\\*oal.dll", MAX_PATH - lstrlenW(srchPath));
283 srchHdl = FindFirstFileW(srchPath, &fdata);
284 if(srchHdl != INVALID_HANDLE_VALUE)
286 do {
287 HMODULE mod;
289 wcsncpy(srchPath, path, MAX_PATH);
290 wcsncat(srchPath, L"\\", MAX_PATH - lstrlenW(srchPath));
291 wcsncat(srchPath, fdata.cFileName, MAX_PATH - lstrlenW(srchPath));
292 TRACE("Found %ls\n", srchPath);
294 mod = LoadLibraryW(srchPath);
295 if(!mod)
296 WARN("Could not load %ls\n", srchPath);
297 else
298 AddModule(mod, fdata.cFileName);
299 } while(FindNextFileW(srchHdl, &fdata));
300 FindClose(srchHdl);
304 static WCHAR *strrchrW(WCHAR *str, WCHAR ch)
306 WCHAR *res = NULL;
307 while(str && *str != '\0')
309 if(*str == ch)
310 res = str;
311 ++str;
313 return res;
316 static int GetLoadedModuleDirectory(const WCHAR *name, WCHAR *moddir, DWORD length)
318 HMODULE module = NULL;
319 WCHAR *sep0, *sep1;
321 if(name)
323 module = GetModuleHandleW(name);
324 if(!module) return 0;
327 if(GetModuleFileNameW(module, moddir, length) == 0)
328 return 0;
330 sep0 = strrchrW(moddir, '/');
331 if(sep0) sep1 = strrchrW(sep0+1, '\\');
332 else sep1 = strrchrW(moddir, '\\');
334 if(sep1) *sep1 = '\0';
335 else if(sep0) *sep0 = '\0';
336 else *moddir = '\0';
338 return 1;
341 void LoadDriverList(void)
343 WCHAR path[MAX_PATH+1] = L"";
344 int len;
346 if(GetLoadedModuleDirectory(L"OpenAL32.dll", path, MAX_PATH))
347 SearchDrivers(path);
349 GetCurrentDirectoryW(MAX_PATH, path);
350 len = lstrlenW(path);
351 if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/'))
352 path[len-1] = '\0';
353 SearchDrivers(path);
355 if(GetLoadedModuleDirectory(NULL, path, MAX_PATH))
356 SearchDrivers(path);
358 GetSystemDirectoryW(path, MAX_PATH);
359 len = lstrlenW(path);
360 if(len > 0 && (path[len-1] == '\\' || path[len-1] == '/'))
361 path[len-1] = '\0';
362 SearchDrivers(path);
366 void InitPtrIntMap(PtrIntMap *map)
368 map->keys = NULL;
369 map->values = NULL;
370 map->size = 0;
371 map->capacity = 0;
372 RWLockInit(&map->lock);
375 void ResetPtrIntMap(PtrIntMap *map)
377 WriteLock(&map->lock);
378 al_free(map->keys);
379 map->keys = NULL;
380 map->values = NULL;
381 map->size = 0;
382 map->capacity = 0;
383 WriteUnlock(&map->lock);
386 ALenum InsertPtrIntMapEntry(PtrIntMap *map, ALvoid *key, ALint value)
388 ALsizei pos = 0;
390 WriteLock(&map->lock);
391 if(map->size > 0)
393 ALsizei count = map->size;
394 do {
395 ALsizei step = count>>1;
396 ALsizei i = pos+step;
397 if(!(map->keys[i] < key))
398 count = step;
399 else
401 pos = i+1;
402 count -= step+1;
404 } while(count > 0);
407 if(pos == map->size || map->keys[pos] != key)
409 if(map->size == map->capacity)
411 ALvoid **keys = NULL;
412 ALint *values;
413 ALsizei newcap;
415 newcap = (map->capacity ? (map->capacity<<1) : 4);
416 if(newcap > map->capacity)
417 keys = al_calloc(16, (sizeof(map->keys[0])+sizeof(map->values[0]))*newcap);
418 if(!keys)
420 WriteUnlock(&map->lock);
421 return AL_OUT_OF_MEMORY;
423 values = (ALint*)&keys[newcap];
425 if(map->keys)
427 memcpy(keys, map->keys, map->size*sizeof(map->keys[0]));
428 memcpy(values, map->values, map->size*sizeof(map->values[0]));
430 al_free(map->keys);
431 map->keys = keys;
432 map->values = values;
433 map->capacity = newcap;
436 if(pos < map->size)
438 memmove(&map->keys[pos+1], &map->keys[pos],
439 (map->size-pos)*sizeof(map->keys[0]));
440 memmove(&map->values[pos+1], &map->values[pos],
441 (map->size-pos)*sizeof(map->values[0]));
443 map->size++;
445 map->keys[pos] = key;
446 map->values[pos] = value;
447 WriteUnlock(&map->lock);
449 return AL_NO_ERROR;
452 ALint RemovePtrIntMapKey(PtrIntMap *map, ALvoid *key)
454 ALint ret = -1;
455 WriteLock(&map->lock);
456 if(map->size > 0)
458 ALsizei pos = 0;
459 ALsizei count = map->size;
460 do {
461 ALsizei step = count>>1;
462 ALsizei i = pos+step;
463 if(!(map->keys[i] < key))
464 count = step;
465 else
467 pos = i+1;
468 count -= step+1;
470 } while(count > 0);
471 if(pos < map->size && map->keys[pos] == key)
473 ret = map->values[pos];
474 if(pos < map->size-1)
476 memmove(&map->keys[pos], &map->keys[pos+1],
477 (map->size-1-pos)*sizeof(map->keys[0]));
478 memmove(&map->values[pos], &map->values[pos+1],
479 (map->size-1-pos)*sizeof(map->values[0]));
481 map->size--;
484 WriteUnlock(&map->lock);
485 return ret;
488 ALint LookupPtrIntMapKey(PtrIntMap *map, ALvoid *key)
490 ALint ret = -1;
491 ReadLock(&map->lock);
492 if(map->size > 0)
494 ALsizei pos = 0;
495 ALsizei count = map->size;
496 do {
497 ALsizei step = count>>1;
498 ALsizei i = pos+step;
499 if(!(map->keys[i] < key))
500 count = step;
501 else
503 pos = i+1;
504 count -= step+1;
506 } while(count > 0);
507 if(pos < map->size && map->keys[pos] == key)
508 ret = map->values[pos];
510 ReadUnlock(&map->lock);
511 return ret;