router.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  1. #include "config.h"
  2. #include "router.h"
  3. #include <algorithm>
  4. #include <array>
  5. #include <cstdio>
  6. #include <cstdlib>
  7. #include <cstring>
  8. #include <string>
  9. #include <string_view>
  10. #include <vector>
  11. #include "AL/alc.h"
  12. #include "AL/al.h"
  13. #include "albit.h"
  14. #include "alstring.h"
  15. #include "opthelpers.h"
  16. #include "strutils.h"
  17. #include "version.h"
  18. eLogLevel LogLevel{eLogLevel::Error};
  19. gsl::owner<std::FILE*> LogFile;
  20. namespace {
  21. std::vector<std::wstring> gAcceptList;
  22. std::vector<std::wstring> gRejectList;
  23. void AddModule(HMODULE module, const std::wstring_view name)
  24. {
  25. for(auto &drv : DriverList)
  26. {
  27. if(drv->Module == module)
  28. {
  29. TRACE("Skipping already-loaded module {}", decltype(std::declval<void*>()){module});
  30. FreeLibrary(module);
  31. return;
  32. }
  33. if(drv->Name == name)
  34. {
  35. TRACE("Skipping similarly-named module {}", wstr_to_utf8(name));
  36. FreeLibrary(module);
  37. return;
  38. }
  39. }
  40. if(!gAcceptList.empty())
  41. {
  42. auto iter = std::find_if(gAcceptList.cbegin(), gAcceptList.cend(),
  43. [name](const std::wstring_view accept)
  44. { return al::case_compare(name, accept) == 0; });
  45. if(iter == gAcceptList.cend())
  46. {
  47. TRACE("{} not found in ALROUTER_ACCEPT, skipping", wstr_to_utf8(name));
  48. FreeLibrary(module);
  49. return;
  50. }
  51. }
  52. if(!gRejectList.empty())
  53. {
  54. auto iter = std::find_if(gRejectList.cbegin(), gRejectList.cend(),
  55. [name](const std::wstring_view accept)
  56. { return al::case_compare(name, accept) == 0; });
  57. if(iter != gRejectList.cend())
  58. {
  59. TRACE("{} found in ALROUTER_REJECT, skipping", wstr_to_utf8(name));
  60. FreeLibrary(module);
  61. return;
  62. }
  63. }
  64. DriverIface &newdrv = *DriverList.emplace_back(std::make_unique<DriverIface>(name, module));
  65. /* Load required functions. */
  66. bool loadok{true};
  67. auto do_load = [module,name](auto &func, const char *fname) -> bool
  68. {
  69. using func_t = std::remove_reference_t<decltype(func)>;
  70. auto ptr = GetProcAddress(module, fname);
  71. if(!ptr)
  72. {
  73. ERR("Failed to find entry point for {} in {}", fname, wstr_to_utf8(name));
  74. return false;
  75. }
  76. func = al::bit_cast<func_t>(ptr);
  77. return true;
  78. };
  79. #define LOAD_PROC(x) loadok &= do_load(newdrv.x, #x)
  80. LOAD_PROC(alcCreateContext);
  81. LOAD_PROC(alcMakeContextCurrent);
  82. LOAD_PROC(alcProcessContext);
  83. LOAD_PROC(alcSuspendContext);
  84. LOAD_PROC(alcDestroyContext);
  85. LOAD_PROC(alcGetCurrentContext);
  86. LOAD_PROC(alcGetContextsDevice);
  87. LOAD_PROC(alcOpenDevice);
  88. LOAD_PROC(alcCloseDevice);
  89. LOAD_PROC(alcGetError);
  90. LOAD_PROC(alcIsExtensionPresent);
  91. LOAD_PROC(alcGetProcAddress);
  92. LOAD_PROC(alcGetEnumValue);
  93. LOAD_PROC(alcGetString);
  94. LOAD_PROC(alcGetIntegerv);
  95. LOAD_PROC(alcCaptureOpenDevice);
  96. LOAD_PROC(alcCaptureCloseDevice);
  97. LOAD_PROC(alcCaptureStart);
  98. LOAD_PROC(alcCaptureStop);
  99. LOAD_PROC(alcCaptureSamples);
  100. LOAD_PROC(alEnable);
  101. LOAD_PROC(alDisable);
  102. LOAD_PROC(alIsEnabled);
  103. LOAD_PROC(alGetString);
  104. LOAD_PROC(alGetBooleanv);
  105. LOAD_PROC(alGetIntegerv);
  106. LOAD_PROC(alGetFloatv);
  107. LOAD_PROC(alGetDoublev);
  108. LOAD_PROC(alGetBoolean);
  109. LOAD_PROC(alGetInteger);
  110. LOAD_PROC(alGetFloat);
  111. LOAD_PROC(alGetDouble);
  112. LOAD_PROC(alGetError);
  113. LOAD_PROC(alIsExtensionPresent);
  114. LOAD_PROC(alGetProcAddress);
  115. LOAD_PROC(alGetEnumValue);
  116. LOAD_PROC(alListenerf);
  117. LOAD_PROC(alListener3f);
  118. LOAD_PROC(alListenerfv);
  119. LOAD_PROC(alListeneri);
  120. LOAD_PROC(alListener3i);
  121. LOAD_PROC(alListeneriv);
  122. LOAD_PROC(alGetListenerf);
  123. LOAD_PROC(alGetListener3f);
  124. LOAD_PROC(alGetListenerfv);
  125. LOAD_PROC(alGetListeneri);
  126. LOAD_PROC(alGetListener3i);
  127. LOAD_PROC(alGetListeneriv);
  128. LOAD_PROC(alGenSources);
  129. LOAD_PROC(alDeleteSources);
  130. LOAD_PROC(alIsSource);
  131. LOAD_PROC(alSourcef);
  132. LOAD_PROC(alSource3f);
  133. LOAD_PROC(alSourcefv);
  134. LOAD_PROC(alSourcei);
  135. LOAD_PROC(alSource3i);
  136. LOAD_PROC(alSourceiv);
  137. LOAD_PROC(alGetSourcef);
  138. LOAD_PROC(alGetSource3f);
  139. LOAD_PROC(alGetSourcefv);
  140. LOAD_PROC(alGetSourcei);
  141. LOAD_PROC(alGetSource3i);
  142. LOAD_PROC(alGetSourceiv);
  143. LOAD_PROC(alSourcePlayv);
  144. LOAD_PROC(alSourceStopv);
  145. LOAD_PROC(alSourceRewindv);
  146. LOAD_PROC(alSourcePausev);
  147. LOAD_PROC(alSourcePlay);
  148. LOAD_PROC(alSourceStop);
  149. LOAD_PROC(alSourceRewind);
  150. LOAD_PROC(alSourcePause);
  151. LOAD_PROC(alSourceQueueBuffers);
  152. LOAD_PROC(alSourceUnqueueBuffers);
  153. LOAD_PROC(alGenBuffers);
  154. LOAD_PROC(alDeleteBuffers);
  155. LOAD_PROC(alIsBuffer);
  156. LOAD_PROC(alBufferData);
  157. LOAD_PROC(alDopplerFactor);
  158. LOAD_PROC(alDopplerVelocity);
  159. LOAD_PROC(alSpeedOfSound);
  160. LOAD_PROC(alDistanceModel);
  161. #undef LOAD_PROC
  162. if(loadok)
  163. {
  164. std::array<ALCint,2> alc_ver{0, 0};
  165. newdrv.alcGetIntegerv(nullptr, ALC_MAJOR_VERSION, 1, &alc_ver[0]);
  166. newdrv.alcGetIntegerv(nullptr, ALC_MINOR_VERSION, 1, &alc_ver[1]);
  167. if(newdrv.alcGetError(nullptr) == ALC_NO_ERROR)
  168. newdrv.ALCVer = MakeALCVer(alc_ver[0], alc_ver[1]);
  169. else
  170. {
  171. WARN("Failed to query ALC version for {}, assuming 1.0", wstr_to_utf8(name));
  172. newdrv.ALCVer = MakeALCVer(1, 0);
  173. }
  174. auto do_load2 = [module,name](auto &func, const char *fname) -> void
  175. {
  176. using func_t = std::remove_reference_t<decltype(func)>;
  177. auto ptr = GetProcAddress(module, fname);
  178. if(!ptr)
  179. WARN("Failed to find optional entry point for {} in {}", fname,
  180. wstr_to_utf8(name));
  181. else
  182. func = al::bit_cast<func_t>(ptr);
  183. };
  184. #define LOAD_PROC(x) do_load2(newdrv.x, #x)
  185. LOAD_PROC(alBufferf);
  186. LOAD_PROC(alBuffer3f);
  187. LOAD_PROC(alBufferfv);
  188. LOAD_PROC(alBufferi);
  189. LOAD_PROC(alBuffer3i);
  190. LOAD_PROC(alBufferiv);
  191. LOAD_PROC(alGetBufferf);
  192. LOAD_PROC(alGetBuffer3f);
  193. LOAD_PROC(alGetBufferfv);
  194. LOAD_PROC(alGetBufferi);
  195. LOAD_PROC(alGetBuffer3i);
  196. LOAD_PROC(alGetBufferiv);
  197. #undef LOAD_PROC
  198. auto do_load3 = [name,&newdrv](auto &func, const char *fname) -> bool
  199. {
  200. using func_t = std::remove_reference_t<decltype(func)>;
  201. auto ptr = newdrv.alcGetProcAddress(nullptr, fname);
  202. if(!ptr)
  203. {
  204. ERR("Failed to find entry point for {} in {}", fname, wstr_to_utf8(name));
  205. return false;
  206. }
  207. func = reinterpret_cast<func_t>(ptr);
  208. return true;
  209. };
  210. #define LOAD_PROC(x) loadok &= do_load3(newdrv.x, #x)
  211. if(newdrv.alcIsExtensionPresent(nullptr, "ALC_EXT_thread_local_context"))
  212. {
  213. LOAD_PROC(alcSetThreadContext);
  214. LOAD_PROC(alcGetThreadContext);
  215. }
  216. #undef LOAD_PROC
  217. }
  218. if(!loadok)
  219. {
  220. DriverList.pop_back();
  221. return;
  222. }
  223. TRACE("Loaded module {}, {}, ALC {}.{}", decltype(std::declval<void*>()){module},
  224. wstr_to_utf8(name), newdrv.ALCVer>>8, newdrv.ALCVer&255);
  225. }
  226. void SearchDrivers(const std::wstring_view path)
  227. {
  228. TRACE("Searching for drivers in {}...", wstr_to_utf8(path));
  229. std::wstring srchPath{path};
  230. srchPath += L"\\*oal.dll";
  231. WIN32_FIND_DATAW fdata{};
  232. HANDLE srchHdl{FindFirstFileW(srchPath.c_str(), &fdata)};
  233. if(srchHdl == INVALID_HANDLE_VALUE) return;
  234. do {
  235. srchPath = path;
  236. srchPath += L"\\";
  237. srchPath += std::data(fdata.cFileName);
  238. TRACE("Found {}", wstr_to_utf8(srchPath));
  239. HMODULE mod{LoadLibraryW(srchPath.c_str())};
  240. if(!mod)
  241. WARN("Could not load {}", wstr_to_utf8(srchPath));
  242. else
  243. AddModule(mod, std::data(fdata.cFileName));
  244. } while(FindNextFileW(srchHdl, &fdata));
  245. FindClose(srchHdl);
  246. }
  247. bool GetLoadedModuleDirectory(const WCHAR *name, std::wstring *moddir)
  248. {
  249. HMODULE module{nullptr};
  250. if(name)
  251. {
  252. module = GetModuleHandleW(name);
  253. if(!module) return false;
  254. }
  255. moddir->assign(256, '\0');
  256. DWORD res{GetModuleFileNameW(module, moddir->data(), static_cast<DWORD>(moddir->size()))};
  257. if(res >= moddir->size())
  258. {
  259. do {
  260. moddir->append(256, '\0');
  261. res = GetModuleFileNameW(module, moddir->data(), static_cast<DWORD>(moddir->size()));
  262. } while(res >= moddir->size());
  263. }
  264. moddir->resize(res);
  265. auto sep0 = moddir->rfind('/');
  266. auto sep1 = moddir->rfind('\\');
  267. if(sep0 < moddir->size() && sep1 < moddir->size())
  268. moddir->resize(std::max(sep0, sep1));
  269. else if(sep0 < moddir->size())
  270. moddir->resize(sep0);
  271. else if(sep1 < moddir->size())
  272. moddir->resize(sep1);
  273. else
  274. moddir->resize(0);
  275. return !moddir->empty();
  276. }
  277. } // namespace
  278. void LoadDriverList()
  279. {
  280. TRACE("Initializing router v0.1-{} {}", ALSOFT_GIT_COMMIT_HASH, ALSOFT_GIT_BRANCH);
  281. if(auto list = al::getenv(L"ALROUTER_ACCEPT"))
  282. {
  283. std::wstring_view namelist{*list};
  284. while(!namelist.empty())
  285. {
  286. auto seppos = namelist.find(',');
  287. if(seppos > 0)
  288. gAcceptList.emplace_back(namelist.substr(0, seppos));
  289. if(seppos < namelist.size())
  290. namelist.remove_prefix(seppos+1);
  291. else
  292. namelist.remove_prefix(namelist.size());
  293. }
  294. }
  295. if(auto list = al::getenv(L"ALROUTER_REJECT"))
  296. {
  297. std::wstring_view namelist{*list};
  298. while(!namelist.empty())
  299. {
  300. auto seppos = namelist.find(',');
  301. if(seppos > 0)
  302. gRejectList.emplace_back(namelist.substr(0, seppos));
  303. if(seppos < namelist.size())
  304. namelist.remove_prefix(seppos+1);
  305. else
  306. namelist.remove_prefix(namelist.size());
  307. }
  308. }
  309. std::wstring dll_path;
  310. if(GetLoadedModuleDirectory(L"OpenAL32.dll", &dll_path))
  311. TRACE("Got DLL path {}", wstr_to_utf8(dll_path));
  312. std::wstring cwd_path;
  313. if(DWORD pathlen{GetCurrentDirectoryW(0, nullptr)})
  314. {
  315. do {
  316. cwd_path.resize(pathlen);
  317. pathlen = GetCurrentDirectoryW(pathlen, cwd_path.data());
  318. } while(pathlen >= cwd_path.size());
  319. cwd_path.resize(pathlen);
  320. }
  321. if(!cwd_path.empty() && (cwd_path.back() == '\\' || cwd_path.back() == '/'))
  322. cwd_path.pop_back();
  323. if(!cwd_path.empty())
  324. TRACE("Got current working directory {}", wstr_to_utf8(cwd_path));
  325. std::wstring proc_path;
  326. if(GetLoadedModuleDirectory(nullptr, &proc_path))
  327. TRACE("Got proc path {}", wstr_to_utf8(proc_path));
  328. std::wstring sys_path;
  329. if(UINT pathlen{GetSystemDirectoryW(nullptr, 0)})
  330. {
  331. do {
  332. sys_path.resize(pathlen);
  333. pathlen = GetSystemDirectoryW(sys_path.data(), pathlen);
  334. } while(pathlen >= sys_path.size());
  335. sys_path.resize(pathlen);
  336. }
  337. if(!sys_path.empty() && (sys_path.back() == '\\' || sys_path.back() == '/'))
  338. sys_path.pop_back();
  339. if(!sys_path.empty())
  340. TRACE("Got system path {}", wstr_to_utf8(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).
  344. */
  345. if(!dll_path.empty() && (cwd_path.empty() || dll_path != cwd_path)
  346. && (proc_path.empty() || dll_path != proc_path)
  347. && (sys_path.empty() || dll_path != sys_path))
  348. SearchDrivers(dll_path);
  349. if(!cwd_path.empty() && (proc_path.empty() || cwd_path != proc_path)
  350. && (sys_path.empty() || cwd_path != sys_path))
  351. SearchDrivers(cwd_path);
  352. if(!proc_path.empty() && (sys_path.empty() || proc_path != sys_path))
  353. SearchDrivers(proc_path);
  354. if(!sys_path.empty())
  355. SearchDrivers(sys_path);
  356. /* Sort drivers that can enumerate device names to the front. */
  357. static constexpr auto is_enumerable = [](DriverIfacePtr &drv)
  358. {
  359. return drv->ALCVer >= MakeALCVer(1, 1)
  360. || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATE_ALL_EXT")
  361. || drv->alcIsExtensionPresent(nullptr, "ALC_ENUMERATION_EXT");
  362. };
  363. std::stable_partition(DriverList.begin(), DriverList.end(), is_enumerable);
  364. /* HACK: rapture3d_oal.dll isn't likely to work if it's one distributed for
  365. * specific games licensed to use it. It will enumerate a Rapture3D device
  366. * but fail to open. This isn't much of a problem, the device just won't
  367. * work for users not allowed to use it. But if it's the first in the list
  368. * where it gets used for the default device, the default device will fail
  369. * to open. Move it down so it's not used for the default device.
  370. */
  371. if(DriverList.size() > 1
  372. && al::case_compare(DriverList.front()->Name, L"rapture3d_oal.dll") == 0)
  373. std::swap(*DriverList.begin(), *(DriverList.begin()+1));
  374. }
  375. BOOL APIENTRY DllMain(HINSTANCE, DWORD reason, void*)
  376. {
  377. switch(reason)
  378. {
  379. case DLL_PROCESS_ATTACH:
  380. if(auto logfname = al::getenv(L"ALROUTER_LOGFILE"))
  381. {
  382. gsl::owner<std::FILE*> f{_wfopen(logfname->c_str(), L"w")};
  383. if(f == nullptr)
  384. ERR("Could not open log file: {}", wstr_to_utf8(*logfname));
  385. else
  386. LogFile = f;
  387. }
  388. if(auto loglev = al::getenv("ALROUTER_LOGLEVEL"))
  389. {
  390. char *end = nullptr;
  391. long l{strtol(loglev->c_str(), &end, 0)};
  392. if(!end || *end != '\0')
  393. ERR("Invalid log level value: {}", *loglev);
  394. else if(l < al::to_underlying(eLogLevel::None)
  395. || l > al::to_underlying(eLogLevel::Trace))
  396. ERR("Log level out of range: {}", *loglev);
  397. else
  398. LogLevel = static_cast<eLogLevel>(l);
  399. }
  400. break;
  401. case DLL_THREAD_ATTACH:
  402. break;
  403. case DLL_THREAD_DETACH:
  404. break;
  405. case DLL_PROCESS_DETACH:
  406. DriverList.clear();
  407. if(LogFile)
  408. fclose(LogFile);
  409. LogFile = nullptr;
  410. break;
  411. }
  412. return TRUE;
  413. }