fix(audio_backend): never throw across the PulseAudio callback boundary

connectContext() throws std::runtime_error when pa_context_connect() fails.
It was called directly from contextStateCb (the libpulse mainloop thread,
running pure-C callback frames) on the PA_CONTEXT_FAILED reconnect path, so on
a pipewire/pulse restart the exception unwound across the C callback boundary
and triggered std::terminate/SIGABRT.

Add reconnectContext() noexcept which wraps connectContext() and logs failures
instead of throwing, and use it from the callback. Guard against the
FAILED -> connect -> FAILED recursion/busy loop with a reentrancy flag. The
constructor-time connectContext() still throws as before.

Fixes #5141.
This commit is contained in:
Alex
2026-07-04 03:14:13 +02:00
parent d3bfec13cc
commit 3831524ba8
2 changed files with 41 additions and 1 deletions
+7
View File
@@ -29,10 +29,17 @@ class AudioBackend {
static void volumeModifyCb(pa_context*, int, void*);
static void sourceVolumeModifyCb(pa_context*, int, void*);
void connectContext();
// Non-throwing reconnect used from the PulseAudio callback thread. Throwing
// across the libpulse C callback boundary calls std::terminate, so this
// swallows any failure and reports it via the return value instead.
bool reconnectContext() noexcept;
pa_threaded_mainloop* mainloop_;
pa_mainloop_api* mainloop_api_;
pa_context* context_;
// Guards against the FAILED -> connect -> FAILED recursion / busy loop when a
// reconnect attempt fails synchronously inside pa_context_connect().
bool reconnecting_{false};
pa_cvolume pa_volume_;
pa_cvolume pa_source_volume_;