Skip to content

Commit 2c8009c

Browse files
committed
fix(pulseaudio): suppress disconnect error during Stream::drop teardown
The play_all driver thread surfaces ClientError::Disconnected when the reactor drops the source's eof_tx — which happens not only on real server disconnect but also as a *direct consequence* of Stream::drop queueing DeletePlaybackStream and the server processing it. The error callback then fires "PulseAudio client disconnected" on every clean teardown, despite the connection being healthy. Check the cancel flag in the play_all spawn before emit_error, mirroring the latency thread's existing pre-poll cancel check. After a clean Stream::drop the cancel flag is already set when play_all unblocks, so the spurious notification is silenced; real disconnects (reactor exits, socket closed) leave the flag clear and still surface through the user's error_callback.
1 parent 9a2c03c commit 2c8009c

2 files changed

Lines changed: 16 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
151151
the driver thread and release the stream, then joins the worker threads
152152
so the delete actually reaches the server before the process exits
153153
(#1188).
154+
- **PulseAudio**: Suppress spurious `StreamInvalidated` ("PulseAudio client
155+
disconnected") error callbacks during cleanup. When `Stream::drop` queues
156+
the delete, the reactor drops the source's `eof_tx` and the `play_all`
157+
driver thread surfaces `ClientError::Disconnected` — even though the
158+
server is fine. The driver-thread spawn now checks the cancel flag before
159+
emitting the error, mirroring the latency thread's existing behaviour.
154160
- **JACK**: Port registration failure now fails stream creation instead of silently failing.
155161
- **JACK**: `activate_async()` failure now returns an error instead of panicking.
156162
- **JACK**: Sample rate is now validated against the live JACK server at stream creation time.

src/host/pulseaudio/stream.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,9 +245,18 @@ impl Stream {
245245
// when the stream is stopped by the user.
246246
let stream_clone = stream.clone();
247247
let error_callback_clone = error_callback.clone();
248+
let cancel_driver = handle.cancel.clone();
248249
let driver_handle = std::thread::spawn(move || {
249250
if let Err(e) = block_on(stream_clone.play_all()) {
250-
emit_error(&error_callback_clone, Error::from(e));
251+
// Stream::drop sets the cancel flag and then queues
252+
// DeletePlaybackStream, which makes the reactor drop the
253+
// source's eof_tx and surfaces here as ClientError::Disconnected.
254+
// That is teardown noise, not a real error — suppress
255+
// emit_error in the cancel case. The latency thread already
256+
// does the equivalent check before each timing_info poll.
257+
if !cancel_driver.load(atomic::Ordering::Relaxed) {
258+
emit_error(&error_callback_clone, Error::from(e));
259+
}
251260
}
252261
});
253262

0 commit comments

Comments
 (0)