20 enum LogLevel LogLevel
= LogLevel_Error
;
23 static void LoadDriverList();
26 BOOL APIENTRY
DllMain(HINSTANCE
, DWORD reason
, void*)
30 case DLL_PROCESS_ATTACH
:
32 if(auto logfname
= al::getenv("ALROUTER_LOGFILE"))
34 FILE *f
= fopen(logfname
->c_str(), "w");
36 ERR("Could not open log file: %s\n", logfname
->c_str());
40 if(auto loglev
= al::getenv("ALROUTER_LOGLEVEL"))
43 long l
= strtol(loglev
->c_str(), &end
, 0);
44 if(!end
|| *end
!= '\0')
45 ERR("Invalid log level value: %s\n", loglev
->c_str());
46 else if(l
< LogLevel_None
|| l
> LogLevel_Trace
)
47 ERR("Log level out of range: %s\n", loglev
->c_str());
49 LogLevel
= static_cast<enum LogLevel
>(l
);
51 TRACE("Initializing router v0.1-%s %s\n", ALSOFT_GIT_COMMIT_HASH
, ALSOFT_GIT_BRANCH
);
56 case DLL_THREAD_ATTACH
:
58 case DLL_THREAD_DETACH
:
61 case DLL_PROCESS_DETACH
:
64 if(LogFile
&& LogFile
!= stderr
)
74 static void AddModule(HMODULE module
, const WCHAR
*name
)
76 for(auto &drv
: DriverList
)
78 if(drv
->Module
== module
)
80 TRACE("Skipping already-loaded module %p\n", decltype(std::declval
<void*>()){module
});
86 TRACE("Skipping similarly-named module %ls\n", name
);
92 DriverList
.emplace_back(std::make_unique
<DriverIface
>(name
, module
));
93 DriverIface
&newdrv
= *DriverList
.back();
95 /* Load required functions. */
97 #define LOAD_PROC(x) do { \
98 newdrv.x = reinterpret_cast<decltype(newdrv.x)>(reinterpret_cast<void*>( \
99 GetProcAddress(module, #x))); \
102 ERR("Failed to find entry point for %s in %ls\n", #x, name); \
106 LOAD_PROC(alcCreateContext
);
107 LOAD_PROC(alcMakeContextCurrent
);
108 LOAD_PROC(alcProcessContext
);
109 LOAD_PROC(alcSuspendContext
);
110 LOAD_PROC(alcDestroyContext
);
111 LOAD_PROC(alcGetCurrentContext
);
112 LOAD_PROC(alcGetContextsDevice
);
113 LOAD_PROC(alcOpenDevice
);
114 LOAD_PROC(alcCloseDevice
);
115 LOAD_PROC(alcGetError
);
116 LOAD_PROC(alcIsExtensionPresent
);
117 LOAD_PROC(alcGetProcAddress
);
118 LOAD_PROC(alcGetEnumValue
);
119 LOAD_PROC(alcGetString
);
120 LOAD_PROC(alcGetIntegerv
);
121 LOAD_PROC(alcCaptureOpenDevice
);
122 LOAD_PROC(alcCaptureCloseDevice
);
123 LOAD_PROC(alcCaptureStart
);
124 LOAD_PROC(alcCaptureStop
);
125 LOAD_PROC(alcCaptureSamples
);
128 LOAD_PROC(alDisable
);
129 LOAD_PROC(alIsEnabled
);
130 LOAD_PROC(alGetString
);
131 LOAD_PROC(alGetBooleanv
);
132 LOAD_PROC(alGetIntegerv
);
133 LOAD_PROC(alGetFloatv
);
134 LOAD_PROC(alGetDoublev
);
135 LOAD_PROC(alGetBoolean
);
136 LOAD_PROC(alGetInteger
);
137 LOAD_PROC(alGetFloat
);
138 LOAD_PROC(alGetDouble
);
139 LOAD_PROC(alGetError
);
140 LOAD_PROC(alIsExtensionPresent
);
141 LOAD_PROC(alGetProcAddress
);
142 LOAD_PROC(alGetEnumValue
);
143 LOAD_PROC(alListenerf
);
144 LOAD_PROC(alListener3f
);
145 LOAD_PROC(alListenerfv
);
146 LOAD_PROC(alListeneri
);
147 LOAD_PROC(alListener3i
);
148 LOAD_PROC(alListeneriv
);
149 LOAD_PROC(alGetListenerf
);
150 LOAD_PROC(alGetListener3f
);
151 LOAD_PROC(alGetListenerfv
);
152 LOAD_PROC(alGetListeneri
);
153 LOAD_PROC(alGetListener3i
);
154 LOAD_PROC(alGetListeneriv
);
155 LOAD_PROC(alGenSources
);
156 LOAD_PROC(alDeleteSources
);
157 LOAD_PROC(alIsSource
);
158 LOAD_PROC(alSourcef
);
159 LOAD_PROC(alSource3f
);
160 LOAD_PROC(alSourcefv
);
161 LOAD_PROC(alSourcei
);
162 LOAD_PROC(alSource3i
);
163 LOAD_PROC(alSourceiv
);
164 LOAD_PROC(alGetSourcef
);
165 LOAD_PROC(alGetSource3f
);
166 LOAD_PROC(alGetSourcefv
);
167 LOAD_PROC(alGetSourcei
);
168 LOAD_PROC(alGetSource3i
);
169 LOAD_PROC(alGetSourceiv
);
170 LOAD_PROC(alSourcePlayv
);
171 LOAD_PROC(alSourceStopv
);
172 LOAD_PROC(alSourceRewindv
);
173 LOAD_PROC(alSourcePausev
);
174 LOAD_PROC(alSourcePlay
);
175 LOAD_PROC(alSourceStop
);
176 LOAD_PROC(alSourceRewind
);
177 LOAD_PROC(alSourcePause
);
178 LOAD_PROC(alSourceQueueBuffers
);
179 LOAD_PROC(alSourceUnqueueBuffers
);
180 LOAD_PROC(alGenBuffers
);
181 LOAD_PROC(alDeleteBuffers
);
182 LOAD_PROC(alIsBuffer
);
183 LOAD_PROC(alBufferData
);
184 LOAD_PROC(alDopplerFactor
);
185 LOAD_PROC(alDopplerVelocity
);
186 LOAD_PROC(alSpeedOfSound
);
187 LOAD_PROC(alDistanceModel
);
190 ALCint alc_ver
[2] = { 0, 0 };
191 newdrv
.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION
, 1, &alc_ver
[0]);
192 newdrv
.alcGetIntegerv(nullptr, ALC_MINOR_VERSION
, 1, &alc_ver
[1]);
193 if(newdrv
.alcGetError(nullptr) == ALC_NO_ERROR
)
194 newdrv
.ALCVer
= MAKE_ALC_VER(alc_ver
[0], alc_ver
[1]);
197 WARN("Failed to query ALC version for %ls, assuming 1.0\n", name
);
198 newdrv
.ALCVer
= MAKE_ALC_VER(1, 0);
202 #define LOAD_PROC(x) do { \
203 newdrv.x = reinterpret_cast<decltype(newdrv.x)>(reinterpret_cast<void*>( \
204 GetProcAddress(module, #x))); \
207 WARN("Failed to find optional entry point for %s in %ls\n", #x, name); \
210 LOAD_PROC(alBufferf
);
211 LOAD_PROC(alBuffer3f
);
212 LOAD_PROC(alBufferfv
);
213 LOAD_PROC(alBufferi
);
214 LOAD_PROC(alBuffer3i
);
215 LOAD_PROC(alBufferiv
);
216 LOAD_PROC(alGetBufferf
);
217 LOAD_PROC(alGetBuffer3f
);
218 LOAD_PROC(alGetBufferfv
);
219 LOAD_PROC(alGetBufferi
);
220 LOAD_PROC(alGetBuffer3i
);
221 LOAD_PROC(alGetBufferiv
);
224 #define LOAD_PROC(x) do { \
225 newdrv.x = reinterpret_cast<decltype(newdrv.x)>( \
226 newdrv.alcGetProcAddress(nullptr, #x)); \
229 ERR("Failed to find entry point for %s in %ls\n", #x, name); \
233 if(newdrv
.alcIsExtensionPresent(nullptr, "ALC_EXT_thread_local_context"))
235 LOAD_PROC(alcSetThreadContext
);
236 LOAD_PROC(alcGetThreadContext
);
242 DriverList
.pop_back();
245 TRACE("Loaded module %p, %ls, ALC %d.%d\n", decltype(std::declval
<void*>()){module
}, name
,
246 newdrv
.ALCVer
>>8, newdrv
.ALCVer
&255);
250 static void SearchDrivers(WCHAR
*path
)
252 WIN32_FIND_DATAW fdata
;
254 TRACE("Searching for drivers in %ls...\n", path
);
255 std::wstring srchPath
= path
;
256 srchPath
+= L
"\\*oal.dll";
258 HANDLE srchHdl
= FindFirstFileW(srchPath
.c_str(), &fdata
);
259 if(srchHdl
!= INVALID_HANDLE_VALUE
)
266 srchPath
+= fdata
.cFileName
;
267 TRACE("Found %ls\n", srchPath
.c_str());
269 mod
= LoadLibraryW(srchPath
.c_str());
271 WARN("Could not load %ls\n", srchPath
.c_str());
273 AddModule(mod
, fdata
.cFileName
);
274 } while(FindNextFileW(srchHdl
, &fdata
));
279 static WCHAR
*strrchrW(WCHAR
*str
, WCHAR ch
)
281 WCHAR
*res
= nullptr;
282 while(str
&& *str
!= '\0')
291 static int GetLoadedModuleDirectory(const WCHAR
*name
, WCHAR
*moddir
, DWORD length
)
293 HMODULE module
= nullptr;
298 module
= GetModuleHandleW(name
);
299 if(!module
) return 0;
302 if(GetModuleFileNameW(module
, moddir
, length
) == 0)
305 sep0
= strrchrW(moddir
, '/');
306 if(sep0
) sep1
= strrchrW(sep0
+1, '\\');
307 else sep1
= strrchrW(moddir
, '\\');
309 if(sep1
) *sep1
= '\0';
310 else if(sep0
) *sep0
= '\0';
316 void LoadDriverList()
318 WCHAR dll_path
[MAX_PATH
+1] = L
"";
319 WCHAR cwd_path
[MAX_PATH
+1] = L
"";
320 WCHAR proc_path
[MAX_PATH
+1] = L
"";
321 WCHAR sys_path
[MAX_PATH
+1] = L
"";
323 if(GetLoadedModuleDirectory(L
"OpenAL32.dll", dll_path
, MAX_PATH
))
324 TRACE("Got DLL path %ls\n", dll_path
);
326 GetCurrentDirectoryW(MAX_PATH
, cwd_path
);
327 auto len
= wcslen(cwd_path
);
328 if(len
> 0 && (cwd_path
[len
-1] == '\\' || cwd_path
[len
-1] == '/'))
329 cwd_path
[len
-1] = '\0';
330 TRACE("Got current working directory %ls\n", cwd_path
);
332 if(GetLoadedModuleDirectory(nullptr, proc_path
, MAX_PATH
))
333 TRACE("Got proc path %ls\n", proc_path
);
335 GetSystemDirectoryW(sys_path
, MAX_PATH
);
336 len
= wcslen(sys_path
);
337 if(len
> 0 && (sys_path
[len
-1] == '\\' || sys_path
[len
-1] == '/'))
338 sys_path
[len
-1] = '\0';
339 TRACE("Got system path %ls\n", sys_path
);
341 /* Don't search the DLL's path if it is the same as the current working
342 * directory, app's path, or system path (don't want to do duplicate
343 * searches, or increase the priority of the app or system path).
346 (!cwd_path
[0] || wcscmp(dll_path
, cwd_path
) != 0) &&
347 (!proc_path
[0] || wcscmp(dll_path
, proc_path
) != 0) &&
348 (!sys_path
[0] || wcscmp(dll_path
, sys_path
) != 0))
349 SearchDrivers(dll_path
);
351 (!proc_path
[0] || wcscmp(cwd_path
, proc_path
) != 0) &&
352 (!sys_path
[0] || wcscmp(cwd_path
, sys_path
) != 0))
353 SearchDrivers(cwd_path
);
354 if(proc_path
[0] && (!sys_path
[0] || wcscmp(proc_path
, sys_path
) != 0))
355 SearchDrivers(proc_path
);
357 SearchDrivers(sys_path
);
361 PtrIntMap::~PtrIntMap()
363 std::lock_guard
<std::mutex
> maplock
{mLock
};
371 ALenum
PtrIntMap::insert(void *key
, int value
)
373 std::lock_guard
<std::mutex
> maplock
{mLock
};
374 auto iter
= std::lower_bound(mKeys
, mKeys
+mSize
, key
);
375 auto pos
= static_cast<ALsizei
>(std::distance(mKeys
, iter
));
377 if(pos
== mSize
|| mKeys
[pos
] != key
)
379 if(mSize
== mCapacity
)
381 void **newkeys
{nullptr};
382 ALsizei newcap
{mCapacity
? (mCapacity
<<1) : 4};
383 if(newcap
> mCapacity
)
384 newkeys
= static_cast<void**>(
385 calloc(newcap
, sizeof(mKeys
[0])+sizeof(mValues
[0])));
387 return AL_OUT_OF_MEMORY
;
388 auto newvalues
= reinterpret_cast<int*>(&newkeys
[newcap
]);
392 std::copy_n(mKeys
, mSize
, newkeys
);
393 std::copy_n(mValues
, mSize
, newvalues
);
403 std::copy_backward(mKeys
+pos
, mKeys
+mSize
, mKeys
+mSize
+1);
404 std::copy_backward(mValues
+pos
, mValues
+mSize
, mValues
+mSize
+1);
409 mValues
[pos
] = value
;
414 int PtrIntMap::removeByKey(void *key
)
418 std::lock_guard
<std::mutex
> maplock
{mLock
};
419 auto iter
= std::lower_bound(mKeys
, mKeys
+mSize
, key
);
420 auto pos
= static_cast<ALsizei
>(std::distance(mKeys
, iter
));
421 if(pos
< mSize
&& mKeys
[pos
] == key
)
426 std::copy(mKeys
+pos
+1, mKeys
+mSize
, mKeys
+pos
);
427 std::copy(mValues
+pos
+1, mValues
+mSize
, mValues
+pos
);
435 int PtrIntMap::lookupByKey(void *key
)
439 std::lock_guard
<std::mutex
> maplock
{mLock
};
440 auto iter
= std::lower_bound(mKeys
, mKeys
+mSize
, key
);
441 auto pos
= static_cast<ALsizei
>(std::distance(mKeys
, iter
));
442 if(pos
< mSize
&& mKeys
[pos
] == key
)