From 3da7aa5be09b43fea3ffc22d7e2cfcce746db641 Mon Sep 17 00:00:00 2001 From: "[ ]" <[ ]> Date: Mon, 5 May 2025 03:16:01 +0900 Subject: [PATCH] feat: Update pipewire backend to support the latest bmsound_wine > minimal necessary implementation for `loopback_signal` bmsound_wine profile --- hooks/audio/implementations/pipewire.cpp | 29 +++++++++++++++++++++--- hooks/audio/implementations/pipewire.h | 3 +++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/hooks/audio/implementations/pipewire.cpp b/hooks/audio/implementations/pipewire.cpp index ac76e29..710bc4f 100644 --- a/hooks/audio/implementations/pipewire.cpp +++ b/hooks/audio/implementations/pipewire.cpp @@ -45,6 +45,7 @@ typedef int(*BmswClientStop_t)(void *); typedef int(*BmswClientDestroy_t)(void *); typedef unsigned char *(*BmswClientGetBuffer_t)(void *, uint32_t); typedef int(*BmswClientReleaseBuffer_t)(void *, uint32_t); +typedef int(*BmswClientAwaitBuffer_t)(void *); typedef void (*BmswClientUpdateCallback_t)(void *, void *, void *); static BmswConfigInit_t BmswConfigInit; [[maybe_unused]] static BmswExperimentalForceProfile_t BmswExperimentalForceProfile; @@ -57,6 +58,7 @@ static BmswClientStop_t BmswClientStop; static BmswClientDestroy_t BmswClientDestroy; static BmswClientGetBuffer_t BmswClientGetBuffer; static BmswClientReleaseBuffer_t BmswClientReleaseBuffer; +static BmswClientAwaitBuffer_t BmswClientAwaitBuffer; [[maybe_unused]] static BmswClientUpdateCallback_t BmswClientUpdateCallback; static HMODULE bmsw_ = nullptr; @@ -93,6 +95,7 @@ HRESULT PipewireBackend::on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *Stre // Initialize pipewire client (without starting the thread) client_ = BmswClientCreate(GAME_INSTANCE->title(), nullptr, nullptr);//(void *)callback_notify,this + notif_ = std::thread(PipewireBackend::notif_poll, this); if (!client_) log_fatal("audio::pipewire", "Client could not be initialized"); @@ -134,7 +137,7 @@ HRESULT PipewireBackend::on_start() noexcept BmswClientStart(client_); return S_OK; } -PipewireBackend::PipewireBackend() : relay_handle_(nullptr), format_(hooks::audio::FORMAT), client_(nullptr) +PipewireBackend::PipewireBackend() : relay_handle_(nullptr), format_(hooks::audio::FORMAT), client_(nullptr), notif_state_(-1) { log_info("audio::pipewire", "{}", __FUNCTION__); @@ -152,6 +155,7 @@ PipewireBackend::PipewireBackend() : relay_handle_(nullptr), format_(hooks::audi BmswClientDestroy = (BmswClientDestroy_t) GetProcAddress(bmsw_, "BmswClientDestroy"); BmswClientGetBuffer = (BmswClientGetBuffer_t) GetProcAddress(bmsw_, "BmswClientGetBuffer"); BmswClientReleaseBuffer = (BmswClientReleaseBuffer_t) GetProcAddress(bmsw_, "BmswClientReleaseBuffer"); + BmswClientAwaitBuffer = (BmswClientAwaitBuffer_t) GetProcAddress(bmsw_, "BmswClientAwaitBuffer"); BmswClientUpdateCallback = (BmswClientUpdateCallback_t) GetProcAddress(bmsw_, "BmswClientUpdateCallback"); // Load config @@ -179,11 +183,21 @@ inline static void callback_notify(void *self) { DWORD last_error = GetLastError(); - log_warning("audio::asio", "AsioBackend::buffer_switch: SetEvent failed: {} ({})", + log_warning("audio::pipewire", "SetEvent failed: {} ({})", last_error, std::system_category().message(last_error)); } } +void PipewireBackend::notif_poll(PipewireBackend *self) +{ + self->notif_state_ = BmswClientAwaitBuffer(self->client_); + while (self->notif_state_ == 1) + { + BmswClientAwaitBuffer(self->client_); + callback_notify(self); + } + self->notif_state_ = -1; +} // Amount in frames of data we may handle at once (which should always end up being what gets send by client, unless overrun happens) HRESULT PipewireBackend::on_get_buffer_size(uint32_t *buffer_frames) noexcept { @@ -228,7 +242,7 @@ HRESULT PipewireBackend::on_release_buffer(uint32_t num_frames_written, DWORD dw } BmswClientReleaseBuffer(client_, num_frames_written); - callback_notify(this); + if(notif_state_ == -1) callback_notify(this); return S_OK; } @@ -243,6 +257,15 @@ HRESULT PipewireBackend::on_stop() noexcept PipewireBackend::~PipewireBackend() { log_info("audio::pipewire", "~PipewireBackend"); + if (notif_state_ == 1) + { + notif_state_ = 0; + notif_.join(); + if (notif_state_ != -1) + { + log_warning("audio::pipewire", "Errors during thread cleanup: '{}'", (const int) notif_state_); + } + } if (client_) BmswClientDestroy(client_); } diff --git a/hooks/audio/implementations/pipewire.h b/hooks/audio/implementations/pipewire.h index f777dc1..ab91100 100644 --- a/hooks/audio/implementations/pipewire.h +++ b/hooks/audio/implementations/pipewire.h @@ -24,12 +24,15 @@ public: 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; + static void notif_poll(PipewireBackend *self); private: int fpc_; REFERENCE_TIME wrt_; const WAVEFORMATEXTENSIBLE &format_; void *client_; + std::thread notif_; + volatile int notif_state_; };