fix(audio): default to shared System output and resolve Auto to a concrete backend (#470)
OOTB playback froze (seekbar advancing, no audio) on hosts where the configured backend was not usable — e.g. PipeWire as the Linux default but `pactl` absent (minimal Debian/Ubuntu). "Auto" (a null backend_type) fell through to a legacy CPAL path that forced the track rate onto the shared default device, producing a suspended/silent stream and leaving a process-wide stuck audio handle that survived Reset. - Add a cross-platform "System" backend (CpalDefaultBackend now on Linux too): opens the OS default output at its negotiated rate with rodio resampling and an explicit ~100ms CPAL buffer (MixerDeviceSink has zero internal buffering, so the bare default underran and stayed suspended). Shared, no exclusivity, no `pactl` — mixes with other apps like any normal player. - Make System the OOTB default and what Reset lands on; seed it on first run. Drop the per-startup #375 NULL->PipeWire backfill migration. - Resolve a null backend_type to System in the player so the legacy CPAL path is never reached (covers legacy installs and headless callers). - "Auto" in Settings is now a resolve-and-set action: it picks the best available backend (PipeWire if available, else System), stores that concrete value and updates the dropdown + device picker, so backend_type is never null. - Explicit PipeWire (DAC passthrough) and ALSA Direct (exclusive) configs are untouched and remain bit-perfect. cc
This commit is contained in:
10 files changed
+111
-75
No files matched your search
@@ -759,16 +759,16 @@ fn try_init_stream_with_backend(
|
||||
channels: u16,
|
||||
state: &SharedState,
|
||||
) -> Option<Result<StreamType, String>> {
|
||||
// Check if backend system is configured.
|
||||
// On macOS, default to SystemDefault when not explicitly set,
|
||||
// so CoreAudio device probing and sample rate switching are active.
|
||||
let backend_type = audio_settings.backend_type.or_else(|| {
|
||||
if cfg!(target_os = "macos") {
|
||||
Some(qbz_audio::AudioBackendType::SystemDefault)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})?;
|
||||
// A None backend_type means "Auto" / unset. Resolve it to SystemDefault on
|
||||
// every platform instead of returning None — returning None made the caller
|
||||
// fall through to the legacy CPAL path, which forced the track rate onto the
|
||||
// shared default device: that froze the seekbar with no audio AND left a
|
||||
// process-wide stuck audio handle that survived Reset (#470). "Auto" is
|
||||
// resolved to a concrete backend in the UI; this is the backend-side safety
|
||||
// net for any remaining None (legacy installs, headless callers).
|
||||
let backend_type = audio_settings
|
||||
.backend_type
|
||||
.unwrap_or(qbz_audio::AudioBackendType::SystemDefault);
|
||||
|
||||
log::info!(
|
||||
"Using backend system: {:?} (device: {:?}, plugin: {:?})",
|
||||
|
||||
Reference in new issue
Block a user