#include "audio.h" #include #include #include #include #include #include "hooks/audio/backends/mmdevice/device_enumerator.h" #include "util/detour.h" #include "util/logging.h" #include "util/memutils.h" #include "audio_private.h" #ifdef _MSC_VER DEFINE_GUID(CLSID_MMDeviceEnumerator, 0xBCDE0395, 0xE52F, 0x467C, 0x8E, 0x3D, 0xC4, 0x57, 0x92, 0x91, 0x69, 0x2E); #endif // function pointers static decltype(CoCreateInstance) *CoCreateInstance_orig = nullptr; namespace hooks::audio { // public globals bool ENABLED = true; bool VOLUME_HOOK_ENABLED = true; bool USE_DUMMY = false; WAVEFORMATEXTENSIBLE FORMAT {}; std::optional BACKEND = std::nullopt; size_t ASIO_DRIVER_ID = 0; bool ASIO_FORCE_UNLOAD_ON_STOP = false; // private globals IAudioClient *CLIENT = nullptr; std::mutex INITIALIZE_LOCK; // for asio } static HRESULT STDAPICALLTYPE CoCreateInstance_hook( REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID *ppv) { // call original HRESULT ret = CoCreateInstance_orig(rclsid, pUnkOuter, dwClsContext, riid, ppv); if (FAILED(ret)) { if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) { log_warning("audio", "CoCreateInstance failed, hr={}", FMT_HRESULT(ret)); } return ret; } // check if this is the audio device enumerator if (IsEqualCLSID(rclsid, CLSID_MMDeviceEnumerator)) { // wrap object auto mmde = reinterpret_cast(ppv); *mmde = new WrappedIMMDeviceEnumerator(*mmde); } // return original result return ret; } namespace hooks::audio { void init() { if (!ENABLED) { return; } log_info("audio", "initializing"); init_low_latency(); // general hooks CoCreateInstance_orig = detour::iat_try("CoCreateInstance", CoCreateInstance_hook); } void stop() { log_info("audio", "stopping"); if (CLIENT) { CLIENT->Stop(); CLIENT->Release(); CLIENT = nullptr; } stop_low_latency(); } }