feat: Update pipewire backend to support the latest bmsound_wine

> minimal necessary implementation for `loopback_signal` bmsound_wine profile
This commit is contained in:
[ ]
2025-05-05 03:16:01 +09:00
parent 40a755173a
commit 3da7aa5be0
2 changed files with 29 additions and 3 deletions
+26 -3
View File
@@ -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_);
}