diff --git a/CMakeLists.txt b/CMakeLists.txt index fa18ba2..5b0dbe6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -472,6 +472,7 @@ set(SOURCE_FILES ${SOURCE_FILES} hooks/audio/backends/wasapi/util.cpp hooks/audio/implementations/asio.cpp hooks/audio/implementations/wave_out.cpp + hooks/audio/implementations/none.cpp hooks/avshook.cpp hooks/cfgmgr32hook.cpp hooks/debughook.cpp diff --git a/hooks/audio/audio.h b/hooks/audio/audio.h index 7ea4517..a86915d 100644 --- a/hooks/audio/audio.h +++ b/hooks/audio/audio.h @@ -13,6 +13,7 @@ namespace hooks::audio { enum class Backend { Asio, WaveOut, + None, }; extern bool ENABLED; @@ -32,6 +33,8 @@ namespace hooks::audio { return Backend::Asio; } else if (_stricmp(value, "waveout") == 0) { return Backend::WaveOut; + } else if (_stricmp(value, "none") == 0) { + return Backend::None; } return std::nullopt; diff --git a/hooks/audio/backends/wasapi/audio_client.cpp b/hooks/audio/backends/wasapi/audio_client.cpp index 222506c..dfa0204 100644 --- a/hooks/audio/backends/wasapi/audio_client.cpp +++ b/hooks/audio/backends/wasapi/audio_client.cpp @@ -9,6 +9,7 @@ #include "hooks/audio/backends/wasapi/util.h" #include "hooks/audio/implementations/asio.h" #include "hooks/audio/implementations/wave_out.h" +#include "hooks/audio/implementations/none.h" //#include "util/co_task_mem_ptr.h" #include "defs.h" @@ -160,6 +161,9 @@ IAudioClient *wrap_audio_client(IAudioClient *audio_client) { case hooks::audio::Backend::WaveOut: backend = new WaveOutBackend(); break; + case hooks::audio::Backend::None: + backend = new NoneBackend(); + break; default: break; } diff --git a/hooks/audio/implementations/none.cpp b/hooks/audio/implementations/none.cpp new file mode 100644 index 0000000..7cffe35 --- /dev/null +++ b/hooks/audio/implementations/none.cpp @@ -0,0 +1,99 @@ +#include "none.h" +#include "hooks/audio/audio.h" +#include "hooks/audio/backends/wasapi/audio_client.h" + + +const WAVEFORMATEXTENSIBLE &NoneBackend::format() const noexcept { + return format_; +} + +HRESULT NoneBackend::on_initialize( + AUDCLNT_SHAREMODE *ShareMode, + DWORD *StreamFlags, + REFERENCE_TIME *hnsBufferDuration, + REFERENCE_TIME *hnsPeriodicity, + const WAVEFORMATEX *pFormat, + LPCGUID AudioSessionGuid) noexcept +{ + *ShareMode = AUDCLNT_SHAREMODE_SHARED; + *StreamFlags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK | + AUDCLNT_STREAMFLAGS_RATEADJUST | + AUDCLNT_STREAMFLAGS_AUTOCONVERTPCM | + AUDCLNT_STREAMFLAGS_SRC_DEFAULT_QUALITY; + *hnsBufferDuration = 100000; + *hnsPeriodicity = 100000; + log_info("audio::none", "on_initialize"); + + return S_OK; +} +HRESULT NoneBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept { + *buffer_frames = 0; + + return S_OK; +} +HRESULT NoneBackend::on_get_stream_latency(REFERENCE_TIME *latency) noexcept { + *latency = 100000; + + return S_OK; +} +HRESULT NoneBackend::on_get_current_padding(std::optional &padding_frames) noexcept { + + padding_frames = 0; + + return S_OK; +} +HRESULT NoneBackend::on_is_format_supported( + AUDCLNT_SHAREMODE *ShareMode, + const WAVEFORMATEX *pFormat, + WAVEFORMATEX **ppClosestMatch) noexcept +{ + // only accept 44.1 kHz, stereo, 16-bits per channel + if (*ShareMode == AUDCLNT_SHAREMODE_EXCLUSIVE && + pFormat->nChannels == 2 && + pFormat->nSamplesPerSec == 44100 && + pFormat->wBitsPerSample == 16) + { + return S_OK; + } + + return AUDCLNT_E_UNSUPPORTED_FORMAT; +} +HRESULT NoneBackend::on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept { + return E_NOTIMPL; +} +HRESULT NoneBackend::on_get_device_period( + REFERENCE_TIME *default_device_period, + REFERENCE_TIME *minimum_device_period) +{ + *default_device_period = 10000; + *minimum_device_period = 10000; + + return S_OK; +} +HRESULT NoneBackend::on_start() noexcept { + return S_OK; +} +HRESULT NoneBackend::on_stop() noexcept { + return S_OK; +} +HRESULT NoneBackend::on_set_event_handle(HANDLE *event_handle) { + + *event_handle = CreateEvent(nullptr, true, false, nullptr); + + return S_OK; +} + +HRESULT NoneBackend::on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) { + static BYTE buf[10000]; + *ppData = buf; + + return S_OK; +} +HRESULT NoneBackend::on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) { + + return S_OK; +} +NoneBackend::NoneBackend() : format_(hooks::audio::FORMAT) +{ + +} diff --git a/hooks/audio/implementations/none.h b/hooks/audio/implementations/none.h new file mode 100644 index 0000000..e595703 --- /dev/null +++ b/hooks/audio/implementations/none.h @@ -0,0 +1,48 @@ +#pragma once + +#include "backend.h" + + +struct NoneBackend final : AudioBackend { +public: + explicit NoneBackend(); + ~NoneBackend() final = default; + + [[nodiscard]] const WAVEFORMATEXTENSIBLE &format() const noexcept override; + + HRESULT on_initialize( + AUDCLNT_SHAREMODE *ShareMode, + DWORD *StreamFlags, + REFERENCE_TIME *hnsBufferDuration, + REFERENCE_TIME *hnsPeriodicity, + const WAVEFORMATEX *pFormat, + LPCGUID AudioSessionGuid) noexcept override; + + HRESULT on_get_buffer_size(uint32_t *buffer_frames) noexcept override; + HRESULT on_get_stream_latency(REFERENCE_TIME *latency) noexcept override; + HRESULT on_get_current_padding(std::optional &padding_frames) noexcept override; + + HRESULT on_is_format_supported( + AUDCLNT_SHAREMODE *ShareMode, + const WAVEFORMATEX *pFormat, + WAVEFORMATEX **ppClosestMatch) noexcept override; + + HRESULT on_get_mix_format(WAVEFORMATEX **pp_device_format) noexcept override; + + HRESULT on_get_device_period( + REFERENCE_TIME *default_device_period, + REFERENCE_TIME *minimum_device_period) override; + + HRESULT on_start() noexcept override; + HRESULT on_stop() noexcept override; + HRESULT on_set_event_handle(HANDLE *event_handle) override; + + HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) override; + HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override; + +private: + + const WAVEFORMATEXTENSIBLE &format_; + BYTE *active_sound_buffer = nullptr; +}; + diff --git a/launcher/options.cpp b/launcher/options.cpp index eb0a799..4fe96f0 100644 --- a/launcher/options.cpp +++ b/launcher/options.cpp @@ -1341,7 +1341,7 @@ static const std::vector OPTION_DEFINITIONS = { " Does nothing for games that do not output to exclusive WASAPI", .type = OptionType::Enum, .category = "Audio", - .elements = {{"asio", "ASIO"}, {"waveout", "waveOut"}}, + .elements = {{"asio", "ASIO"}, {"waveout", "waveOut"},{"none", "None"}}, }, { .title = "Spice Audio Hook ASIO Driver ID",