From 249e30766e9359494e539554b1b049c3cd7fa4e6 Mon Sep 17 00:00:00 2001 From: vicrodh <103399283+vicrodh@users.noreply.github.com> Date: Thu, 27 Aug 2026 12:44:20 -0600 Subject: [PATCH] fix(audio): skip the Linux stack probes on Windows A spawn of an image that does not exist fails before a process is created, so pactl, pw-dump and systemctl were harmless on Windows. sh is not: it exists wherever Git for Windows is installed, so the five sh -c probes in audio_stack_health really ran and flashed five console windows past a GUI-subsystem binary that owns no console. Scoped to windows / not(windows), NOT to linux / not(linux). macOS and the BSDs can have a real pactl or pw-dump from Homebrew or ports, and answering false for them would take away an answer they can give. qbz-theme needed nothing: its dispatch is by XDG_CURRENT_DESKTOP, so Windows resolves DesktopEnvironment::Unknown, whose arm returns Err without calling any desktop probe. cc --- crates/qbz-audio/src/dac_probe.rs | 14 ++++++++++++++ crates/qbz-audio/src/health.rs | 30 ++++++++++++++++++++++++++++- crates/qbz-qt/src/diagnostics_qt.rs | 10 ++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/crates/qbz-audio/src/dac_probe.rs b/crates/qbz-audio/src/dac_probe.rs index 7d6f2fc1e..bb92fce8b 100644 --- a/crates/qbz-audio/src/dac_probe.rs +++ b/crates/qbz-audio/src/dac_probe.rs @@ -11,6 +11,8 @@ //! bit-perfect / sample-rate-passthrough path is untouched. use serde::{Deserialize, Serialize}; +// Every target but Windows still runs `pw-dump`. +#[cfg(not(windows))] use std::process::Command; /// The DAC's live, negotiated hardware state — what the card is REALLY clocked @@ -94,6 +96,18 @@ pub fn parse_alsa_card_for_node(json: &str, node_name: &str) -> Option { } /// Resolve the ALSA card number for a sink node by running `pw-dump`. +/// +/// W14, Windows only: `pw-dump` does not exist there, so the spawn already +/// failed into this same None. Scoped to Windows rather than `not(linux)` -- +/// a macOS or BSD box can have a real `pw-dump`, and this function is not the +/// place to decide it may not speak. +#[cfg(windows)] +fn alsa_card_for_node(_node_name: &str) -> Option { + None +} + +/// Resolve the ALSA card number for a sink node by running `pw-dump`. +#[cfg(not(windows))] fn alsa_card_for_node(node_name: &str) -> Option { let output = Command::new("pw-dump").output().ok()?; if !output.status.success() { diff --git a/crates/qbz-audio/src/health.rs b/crates/qbz-audio/src/health.rs index e1de1b85f..1db1fa5e7 100644 --- a/crates/qbz-audio/src/health.rs +++ b/crates/qbz-audio/src/health.rs @@ -5,6 +5,8 @@ //! the check step can show the right `apt`/`dnf`/`pacman` remediation. None of //! this opens a stream — purely diagnostic. +// Every target but Windows still probes; see `audio_stack_health`. +#[cfg(not(windows))] use std::process::Command; /// Result of the audio-stack probes. All best-effort; a failed probe reads as @@ -32,7 +34,8 @@ impl AudioStackHealth { } } -/// True if `sh -c ""` exits 0. +/// True if `sh -c ""` exits 0. Windows never probes; see below. +#[cfg(not(windows))] fn sh_ok(probe: &str) -> bool { Command::new("sh") .arg("-c") @@ -44,6 +47,31 @@ fn sh_ok(probe: &str) -> bool { /// Run the audio-stack probes. Linux-only meaningfully; elsewhere everything /// reads false except where trivially true. +/// +/// W14: on WINDOWS ONLY the answer is all-false, returned WITHOUT running the +/// probes. `systemctl`, `pactl` and `pw-dump` do not exist there (a spawn of a +/// missing image fails before a process is made, which is harmless), but `sh` +/// DOES exist wherever Git for Windows is installed, so the five `sh -c` +/// probes really run and flash five console windows past a GUI-subsystem +/// binary that owns no console. +/// +/// Scoped to Windows, not to `not(linux)`: macOS and the BSDs can have a real +/// `pactl`/`pw-dump` from Homebrew or ports, and answering false for them +/// would be a lie this diff has no business telling. +#[cfg(windows)] +pub fn audio_stack_health() -> AudioStackHealth { + AudioStackHealth { + wireplumber_active: false, + has_pw_dump: false, + cpal_sees_pipewire: false, + has_pactl: false, + any_devices: false, + } +} + +/// Run the audio-stack probes. Linux-only meaningfully; elsewhere everything +/// reads false except where trivially true. +#[cfg(not(windows))] pub fn audio_stack_health() -> AudioStackHealth { // systemd path first; fall back to a process check so non-systemd inits // (Gentoo/OpenRC, Void/runit) don't read as "WirePlumber down". diff --git a/crates/qbz-qt/src/diagnostics_qt.rs b/crates/qbz-qt/src/diagnostics_qt.rs index f65de1f6f..e973b6f56 100644 --- a/crates/qbz-qt/src/diagnostics_qt.rs +++ b/crates/qbz-qt/src/diagnostics_qt.rs @@ -1163,6 +1163,16 @@ fn collect_output_sinks() -> (Option, Vec, Option<(String, Strin /// right now (vs the saved "Preferred Sample Rate"). Linux/PipeWire/Pulse only; /// `None` when pactl is unavailable (a Flatpak/Snap sandbox without it simply /// degrades to "—", same as the reference). READ-ONLY. +/// W14, Windows only: `pactl` is a Pulse/PipeWire tool and does not exist on +/// Windows, so the row degrades to the same "-" the missing-pactl path already +/// produced -- without the spawn. macOS and the BSDs keep probing: a Homebrew +/// or ports `pactl` there is real and can answer. +#[cfg(windows)] +fn active_sink_format() -> Option<(String, String)> { + None +} + +#[cfg(not(windows))] fn active_sink_format() -> Option<(String, String)> { use std::process::Command; let default = Command::new("pactl")