Skip to content

Commit 5597cb7

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 792456e commit 5597cb7

2 files changed

Lines changed: 8 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
145145
- **JACK**: Poisoned error callback mutex no longer silently drops subsequent error notifications.
146146
- **PulseAudio**: Poisoned locks now exit the thread gracefully instead of panicking.
147147
- **PulseAudio**: Fix server-side stream leak when a `Stream` is dropped.
148+
- **PulseAudio**: Remove spurious "PulseAudio client disconnected" warnings during stream cleanup.
148149
- **JACK**: Port registration failure now fails stream creation instead of silently failing.
149150
- **JACK**: `activate_async()` failure now returns an error instead of panicking.
150151
- **JACK**: Sample rate is now validated against the live JACK server at stream creation time.

src/host/pulseaudio/stream.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,9 +239,15 @@ impl Stream {
239239
// when the stream is stopped by the user.
240240
let stream_clone = stream.clone();
241241
let error_callback_clone = error_callback.clone();
242+
let cancel_driver = handle.cancel.clone();
242243
let driver_handle = std::thread::spawn(move || {
243244
if let Err(e) = block_on(stream_clone.play_all()) {
244-
emit_error(&error_callback_clone, Error::from(e));
245+
// A server playback error is expected when the client
246+
// closes their stream. No need to report it back to
247+
// the client.
248+
if !cancel_driver.load(atomic::Ordering::Relaxed) {
249+
emit_error(&error_callback_clone, Error::from(e));
250+
}
245251
}
246252
});
247253

0 commit comments

Comments
 (0)