Skip to main content

rightkit_qa/
audio.rs

1//! Audio is always muted during QA. Apps are told through `RIGHTKIT_QA_MUTE=1`
2//! and Chrome gets `--mute-audio`; on macOS the system output can additionally
3//! be muted for the run and restored afterwards (opt-in, restored on drop).
4//! Playback is asserted from DOM/engine state, never from sound.
5#[cfg(target_os = "macos")]
6use std::process::{Command, Stdio};
7
8pub struct SystemMute {
9    restore: Option<bool>,
10}
11
12impl SystemMute {
13    /// Mute system output (macOS only). A no-op elsewhere; `active()` reports it.
14    pub fn engage() -> Self {
15        #[cfg(target_os = "macos")]
16        {
17            let was = Command::new("osascript")
18                .args(["-e", "output muted of (get volume settings)"])
19                .output()
20                .ok()
21                .map(|o| String::from_utf8_lossy(&o.stdout).trim() == "true");
22            if let Some(was_muted) = was {
23                if !was_muted {
24                    let _ = Command::new("osascript")
25                        .args(["-e", "set volume with output muted"])
26                        .stdout(Stdio::null())
27                        .stderr(Stdio::null())
28                        .status();
29                }
30                return Self {
31                    restore: Some(was_muted),
32                };
33            }
34        }
35        Self { restore: None }
36    }
37    pub fn active(&self) -> bool {
38        self.restore.is_some()
39    }
40}
41
42impl Drop for SystemMute {
43    fn drop(&mut self) {
44        // Only the macOS path ever records a mute to restore.
45        #[cfg(target_os = "macos")]
46        if self.restore == Some(false) {
47            let _ = Command::new("osascript")
48                .args(["-e", "set volume without output muted"])
49                .stdout(Stdio::null())
50                .stderr(Stdio::null())
51                .status();
52        }
53    }
54}