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 int(*BmswClientDestroy_t)(void *);
typedef unsigned char *(*BmswClientGetBuffer_t)(void *, uint32_t); typedef unsigned char *(*BmswClientGetBuffer_t)(void *, uint32_t);
typedef int(*BmswClientReleaseBuffer_t)(void *, uint32_t); typedef int(*BmswClientReleaseBuffer_t)(void *, uint32_t);
typedef int(*BmswClientAwaitBuffer_t)(void *);
typedef void (*BmswClientUpdateCallback_t)(void *, void *, void *); typedef void (*BmswClientUpdateCallback_t)(void *, void *, void *);
static BmswConfigInit_t BmswConfigInit; static BmswConfigInit_t BmswConfigInit;
[[maybe_unused]] static BmswExperimentalForceProfile_t BmswExperimentalForceProfile; [[maybe_unused]] static BmswExperimentalForceProfile_t BmswExperimentalForceProfile;
@@ -57,6 +58,7 @@ static BmswClientStop_t BmswClientStop;
static BmswClientDestroy_t BmswClientDestroy; static BmswClientDestroy_t BmswClientDestroy;
static BmswClientGetBuffer_t BmswClientGetBuffer; static BmswClientGetBuffer_t BmswClientGetBuffer;
static BmswClientReleaseBuffer_t BmswClientReleaseBuffer; static BmswClientReleaseBuffer_t BmswClientReleaseBuffer;
static BmswClientAwaitBuffer_t BmswClientAwaitBuffer;
[[maybe_unused]] static BmswClientUpdateCallback_t BmswClientUpdateCallback; [[maybe_unused]] static BmswClientUpdateCallback_t BmswClientUpdateCallback;
static HMODULE bmsw_ = nullptr; static HMODULE bmsw_ = nullptr;
@@ -93,6 +95,7 @@ HRESULT PipewireBackend::on_initialize(AUDCLNT_SHAREMODE *ShareMode, DWORD *Stre
// Initialize pipewire client (without starting the thread) // Initialize pipewire client (without starting the thread)
client_ = BmswClientCreate(GAME_INSTANCE->title(), nullptr, nullptr);//(void *)callback_notify,this client_ = BmswClientCreate(GAME_INSTANCE->title(), nullptr, nullptr);//(void *)callback_notify,this
notif_ = std::thread(PipewireBackend::notif_poll, this);
if (!client_) if (!client_)
log_fatal("audio::pipewire", "Client could not be initialized"); log_fatal("audio::pipewire", "Client could not be initialized");
@@ -134,7 +137,7 @@ HRESULT PipewireBackend::on_start() noexcept
BmswClientStart(client_); BmswClientStart(client_);
return S_OK; 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__); log_info("audio::pipewire", "{}", __FUNCTION__);
@@ -152,6 +155,7 @@ PipewireBackend::PipewireBackend() : relay_handle_(nullptr), format_(hooks::audi
BmswClientDestroy = (BmswClientDestroy_t) GetProcAddress(bmsw_, "BmswClientDestroy"); BmswClientDestroy = (BmswClientDestroy_t) GetProcAddress(bmsw_, "BmswClientDestroy");
BmswClientGetBuffer = (BmswClientGetBuffer_t) GetProcAddress(bmsw_, "BmswClientGetBuffer"); BmswClientGetBuffer = (BmswClientGetBuffer_t) GetProcAddress(bmsw_, "BmswClientGetBuffer");
BmswClientReleaseBuffer = (BmswClientReleaseBuffer_t) GetProcAddress(bmsw_, "BmswClientReleaseBuffer"); BmswClientReleaseBuffer = (BmswClientReleaseBuffer_t) GetProcAddress(bmsw_, "BmswClientReleaseBuffer");
BmswClientAwaitBuffer = (BmswClientAwaitBuffer_t) GetProcAddress(bmsw_, "BmswClientAwaitBuffer");
BmswClientUpdateCallback = (BmswClientUpdateCallback_t) GetProcAddress(bmsw_, "BmswClientUpdateCallback"); BmswClientUpdateCallback = (BmswClientUpdateCallback_t) GetProcAddress(bmsw_, "BmswClientUpdateCallback");
// Load config // Load config
@@ -179,11 +183,21 @@ inline static void callback_notify(void *self)
{ {
DWORD last_error = GetLastError(); DWORD last_error = GetLastError();
log_warning("audio::asio", "AsioBackend::buffer_switch: SetEvent failed: {} ({})", log_warning("audio::pipewire", "SetEvent failed: {} ({})",
last_error, last_error,
std::system_category().message(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) // 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 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); BmswClientReleaseBuffer(client_, num_frames_written);
callback_notify(this); if(notif_state_ == -1) callback_notify(this);
return S_OK; return S_OK;
} }
@@ -243,6 +257,15 @@ HRESULT PipewireBackend::on_stop() noexcept
PipewireBackend::~PipewireBackend() PipewireBackend::~PipewireBackend()
{ {
log_info("audio::pipewire", "~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_); if (client_) BmswClientDestroy(client_);
} }
+3
View File
@@ -24,12 +24,15 @@ public:
HRESULT on_set_event_handle(HANDLE *event_handle) override; HRESULT on_set_event_handle(HANDLE *event_handle) override;
HRESULT on_get_buffer(uint32_t num_frames_requested, BYTE **ppData) 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; HRESULT on_release_buffer(uint32_t num_frames_written, DWORD dwFlags) override;
static void notif_poll(PipewireBackend *self);
private: private:
int fpc_; int fpc_;
REFERENCE_TIME wrt_; REFERENCE_TIME wrt_;
const WAVEFORMATEXTENSIBLE &format_; const WAVEFORMATEXTENSIBLE &format_;
void *client_; void *client_;
std::thread notif_;
volatile int notif_state_;
}; };