diff --git a/src/common/deps.rs b/src/common/deps.rs index 8c89d84..f36920f 100644 --- a/src/common/deps.rs +++ b/src/common/deps.rs @@ -8,6 +8,7 @@ pub fn check_host_binaries(display: DisplayServer) -> Result<()> { if display == DisplayServer::Wayland { require("gst-launch-1.0")?; require("gst-inspect-1.0")?; + require("pactl")?; require_gst_element("pipewiresrc")?; require_gst_element("vah264enc")?; require_gst_element("h264parse")?; @@ -61,6 +62,13 @@ fn install_hint_for_bin(bin: &str) -> String { Some("fedora" | "nobara") => "gstreamer1 gstreamer1-plugins-base-tools", _ => "gstreamer + tools", }, + "pactl" => match distro.as_deref() { + Some("arch" | "cachyos" | "manjaro" | "endeavouros") => "libpulse", + Some("debian" | "ubuntu" | "pop" | "linuxmint") => "pulseaudio-utils", + Some("fedora" | "nobara") => "pulseaudio-utils", + Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "pulseaudio-utils", + _ => "pulseaudio-utils (provides `pactl`)", + }, _ => bin, }; install_command(&distro, pkg) diff --git a/src/host/wayland.rs b/src/host/wayland.rs index 92a9986..bb30d0e 100644 --- a/src/host/wayland.rs +++ b/src/host/wayland.rs @@ -121,6 +121,8 @@ pub async fn start(opts: &HostOpts) -> Result { // no codec assumptions. let key_interval = (opts.framerate * 2).to_string(); let bitrate = opts.bitrate.to_string(); + let audio_monitor = default_audio_monitor().await?; + let audio_device = format!("device={audio_monitor}"); let mut gst_cmd = Command::new("gst-launch-1.0"); gst_cmd .args([ @@ -161,8 +163,10 @@ pub async fn start(opts: &HostOpts) -> Result { "video/x-h264,stream-format=byte-stream,alignment=au", "!", "mux.", - // audio branch + // audio branch — capture the default sink's MONITOR (system audio + // out), not the default source (which is the mic). "pulsesrc", + &audio_device, "do-timestamp=true", "!", "queue", @@ -274,3 +278,25 @@ pub async fn connect_to_capture(port: u16, max_wait: Duration) -> Result Result { + let output = Command::new("pactl") + .arg("get-default-sink") + .output() + .await + .context("failed to run `pactl get-default-sink` (install pulseaudio-utils or pipewire-pulse)")?; + if !output.status.success() { + bail!( + "pactl get-default-sink failed: {}", + String::from_utf8_lossy(&output.stderr).trim() + ); + } + let sink = String::from_utf8(output.stdout) + .context("default sink name was not UTF-8")? + .trim() + .to_string(); + if sink.is_empty() { + bail!("pactl get-default-sink returned no name (is a sound server running?)"); + } + Ok(format!("{sink}.monitor")) +}