A newer rustfmt wraps over-long match arms and call expressions that the version main was last formatted with left on one line. Pure formatting, no semantic change — split out so the friends-list feature commits stay focused on real changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
222 lines
9.2 KiB
Rust
222 lines
9.2 KiB
Rust
use anyhow::{Result, bail};
|
|
use std::path::PathBuf;
|
|
use std::process::Command;
|
|
|
|
use crate::cli::HostOpts;
|
|
use crate::common::display::DisplayServer;
|
|
|
|
pub fn check_host_binaries(display: DisplayServer, opts: &HostOpts) -> Result<()> {
|
|
// Unknown is handled (and rejected) by the caller; nothing to check here.
|
|
if display == DisplayServer::Unknown {
|
|
return Ok(());
|
|
}
|
|
|
|
// Shared across both backends: the gst tools, audio routing, and the
|
|
// encode/mux tail elements.
|
|
require("gst-launch-1.0")?;
|
|
require("gst-inspect-1.0")?;
|
|
require("pactl")?;
|
|
// videoscale (downscale for the quality presets) lives in plugins-base,
|
|
// the same package the gst tools need, so this rarely fails on its own —
|
|
// but check it for a clear error if a partial install is missing it.
|
|
require_gst_element("videoscale")?;
|
|
require_gst_element("h264parse")?;
|
|
require_gst_element("mpegtsmux")?;
|
|
require_gst_element("pulsesrc")?;
|
|
require_gst_element("avenc_aac")?;
|
|
require_gst_element("aacparse")?;
|
|
|
|
// Encoder depends on --no-hwencode (software x264 vs hardware VAAPI).
|
|
if opts.no_hwencode {
|
|
require_gst_element("x264enc")?;
|
|
} else {
|
|
require_gst_element("vah264enc")?;
|
|
}
|
|
|
|
// Per-backend video source, plus the X11 window-picker when --window is set.
|
|
match display {
|
|
DisplayServer::Wayland => require_gst_element("pipewiresrc")?,
|
|
DisplayServer::X11 => {
|
|
require_gst_element("ximagesrc")?;
|
|
if opts.window {
|
|
require("xwininfo")?;
|
|
}
|
|
}
|
|
DisplayServer::Unknown => unreachable!("early-returned above"),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn require(bin: &str) -> Result<PathBuf> {
|
|
match which(bin) {
|
|
Some(p) => Ok(p),
|
|
None => bail!("`{bin}` not found on PATH.\n{}", install_hint_for_bin(bin)),
|
|
}
|
|
}
|
|
|
|
fn require_gst_element(name: &str) -> Result<()> {
|
|
let ok = Command::new("gst-inspect-1.0")
|
|
.args(["--exists", name])
|
|
.status()
|
|
.map(|s| s.success())
|
|
.unwrap_or(false);
|
|
if !ok {
|
|
bail!(
|
|
"GStreamer element `{name}` not available.\n{}",
|
|
install_hint_for_gst_element(name)
|
|
);
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn which(bin: &str) -> Option<PathBuf> {
|
|
let path = std::env::var_os("PATH")?;
|
|
for dir in std::env::split_paths(&path) {
|
|
let candidate = dir.join(bin);
|
|
if candidate.is_file() {
|
|
return Some(candidate);
|
|
}
|
|
}
|
|
None
|
|
}
|
|
|
|
fn install_hint_for_bin(bin: &str) -> String {
|
|
let distro = detect_distro();
|
|
let pkg = match bin {
|
|
"gst-launch-1.0" | "gst-inspect-1.0" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gstreamer gst-plugins-base"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-tools",
|
|
Some("fedora" | "nobara") => "gstreamer1 gstreamer1-plugins-base-tools",
|
|
_ => "gstreamer + tools",
|
|
},
|
|
"pactl" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "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`)",
|
|
},
|
|
"xwininfo" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"xorg-xwininfo"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "x11-utils",
|
|
Some("fedora" | "nobara") => "xorg-x11-utils",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "xwininfo",
|
|
_ => "xwininfo (X11 window-info utility)",
|
|
},
|
|
_ => bin,
|
|
};
|
|
install_command(&distro, pkg)
|
|
}
|
|
|
|
fn install_hint_for_gst_element(name: &str) -> String {
|
|
let distro = detect_distro();
|
|
let pkg = match name {
|
|
"pipewiresrc" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugin-pipewire"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pipewire",
|
|
Some("fedora" | "nobara") => "pipewire-gstreamer",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "pipewire-gstreamer",
|
|
_ => "the GStreamer PipeWire plugin",
|
|
},
|
|
"vah264enc" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugin-va"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad",
|
|
_ => {
|
|
"the GStreamer VA-API plugin (requires an H.264-capable GPU; almost all modern GPUs)"
|
|
}
|
|
},
|
|
"x264enc" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugins-ugly"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-ugly",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-ugly",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-ugly",
|
|
_ => "the GStreamer x264 plugin (plugins-ugly)",
|
|
},
|
|
"ximagesrc" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugins-good"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-good",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-good",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good",
|
|
_ => "the GStreamer X11 plugin (plugins-good)",
|
|
},
|
|
"videoscale" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugins-base"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-base",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-base",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-base",
|
|
_ => "the GStreamer plugins-base set",
|
|
},
|
|
"h264parse" | "mpegtsmux" | "aacparse" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugins-bad"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad",
|
|
_ => "the GStreamer plugins-bad set",
|
|
},
|
|
"pulsesrc" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-plugins-good"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pulseaudio",
|
|
Some("fedora" | "nobara") => "gstreamer1-plugins-good",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good",
|
|
_ => "the GStreamer PulseAudio plugin",
|
|
},
|
|
"avenc_aac" => match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
"gst-libav"
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-libav",
|
|
Some("fedora" | "nobara") => "gstreamer1-libav",
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-libav",
|
|
_ => "the GStreamer libav (avenc) plugin",
|
|
},
|
|
_ => name,
|
|
};
|
|
install_command(&distro, pkg)
|
|
}
|
|
|
|
fn install_command(distro: &Option<String>, pkg: &str) -> String {
|
|
let cmd = match distro.as_deref() {
|
|
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
|
|
format!("sudo pacman -S {pkg}")
|
|
}
|
|
Some("debian" | "ubuntu" | "pop" | "linuxmint") => format!("sudo apt install {pkg}"),
|
|
Some("fedora" | "nobara") => format!("sudo dnf install {pkg}"),
|
|
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => {
|
|
format!("sudo zypper install {pkg}")
|
|
}
|
|
_ => format!("install the `{pkg}` package via your distro's package manager"),
|
|
};
|
|
format!("Install hint: {cmd}")
|
|
}
|
|
|
|
fn detect_distro() -> Option<String> {
|
|
let contents = std::fs::read_to_string("/etc/os-release").ok()?;
|
|
for line in contents.lines() {
|
|
if let Some(rest) = line.strip_prefix("ID=") {
|
|
return Some(rest.trim_matches('"').to_lowercase());
|
|
}
|
|
}
|
|
None
|
|
}
|