style: apply current rustfmt to the tree

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>
This commit is contained in:
2026-05-30 16:25:33 -04:00
parent 9b9328f6a9
commit 14fc1af716
11 changed files with 174 additions and 71 deletions
+2 -5
View File
@@ -84,7 +84,6 @@ pub enum BandwidthStatus {
Failed, Failed,
} }
fn default_status() -> BandwidthStatus { fn default_status() -> BandwidthStatus {
BandwidthStatus::Unmeasured BandwidthStatus::Unmeasured
} }
@@ -116,11 +115,9 @@ pub fn save(cfg: &Config) -> Result<()> {
let parent = path let parent = path
.parent() .parent()
.context("config path has no parent directory")?; .context("config path has no parent directory")?;
fs::create_dir_all(parent) fs::create_dir_all(parent).with_context(|| format!("failed to create {}", parent.display()))?;
.with_context(|| format!("failed to create {}", parent.display()))?;
let serialized = let serialized = toml::to_string_pretty(cfg).context("failed to serialize config to TOML")?;
toml::to_string_pretty(cfg).context("failed to serialize config to TOML")?;
let tmp = parent.join(format!(".config.toml.tmp.{}", std::process::id())); let tmp = parent.join(format!(".config.toml.tmp.{}", std::process::id()));
{ {
+39 -13
View File
@@ -85,7 +85,9 @@ fn install_hint_for_bin(bin: &str) -> String {
let distro = detect_distro(); let distro = detect_distro();
let pkg = match bin { let pkg = match bin {
"gst-launch-1.0" | "gst-inspect-1.0" => match distro.as_deref() { "gst-launch-1.0" | "gst-inspect-1.0" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gstreamer gst-plugins-base", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gstreamer gst-plugins-base"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-tools", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-tools",
Some("fedora" | "nobara") => "gstreamer1 gstreamer1-plugins-base-tools", Some("fedora" | "nobara") => "gstreamer1 gstreamer1-plugins-base-tools",
_ => "gstreamer + tools", _ => "gstreamer + tools",
@@ -98,7 +100,9 @@ fn install_hint_for_bin(bin: &str) -> String {
_ => "pulseaudio-utils (provides `pactl`)", _ => "pulseaudio-utils (provides `pactl`)",
}, },
"xwininfo" => match distro.as_deref() { "xwininfo" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "xorg-xwininfo", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"xorg-xwininfo"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "x11-utils", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "x11-utils",
Some("fedora" | "nobara") => "xorg-x11-utils", Some("fedora" | "nobara") => "xorg-x11-utils",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "xwininfo", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "xwininfo",
@@ -113,56 +117,74 @@ fn install_hint_for_gst_element(name: &str) -> String {
let distro = detect_distro(); let distro = detect_distro();
let pkg = match name { let pkg = match name {
"pipewiresrc" => match distro.as_deref() { "pipewiresrc" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugin-pipewire", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugin-pipewire"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pipewire", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pipewire",
Some("fedora" | "nobara") => "pipewire-gstreamer", Some("fedora" | "nobara") => "pipewire-gstreamer",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "pipewire-gstreamer", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "pipewire-gstreamer",
_ => "the GStreamer PipeWire plugin", _ => "the GStreamer PipeWire plugin",
}, },
"vah264enc" => match distro.as_deref() { "vah264enc" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugin-va", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugin-va"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad",
Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free", Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad",
_ => "the GStreamer VA-API plugin (requires an H.264-capable GPU; almost all modern GPUs)", _ => {
"the GStreamer VA-API plugin (requires an H.264-capable GPU; almost all modern GPUs)"
}
}, },
"x264enc" => match distro.as_deref() { "x264enc" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugins-ugly", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugins-ugly"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-ugly", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-ugly",
Some("fedora" | "nobara") => "gstreamer1-plugins-ugly", Some("fedora" | "nobara") => "gstreamer1-plugins-ugly",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-ugly", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-ugly",
_ => "the GStreamer x264 plugin (plugins-ugly)", _ => "the GStreamer x264 plugin (plugins-ugly)",
}, },
"ximagesrc" => match distro.as_deref() { "ximagesrc" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugins-good", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugins-good"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-good", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-good",
Some("fedora" | "nobara") => "gstreamer1-plugins-good", Some("fedora" | "nobara") => "gstreamer1-plugins-good",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good",
_ => "the GStreamer X11 plugin (plugins-good)", _ => "the GStreamer X11 plugin (plugins-good)",
}, },
"videoscale" => match distro.as_deref() { "videoscale" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugins-base", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugins-base"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-base", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-base",
Some("fedora" | "nobara") => "gstreamer1-plugins-base", Some("fedora" | "nobara") => "gstreamer1-plugins-base",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-base", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-base",
_ => "the GStreamer plugins-base set", _ => "the GStreamer plugins-base set",
}, },
"h264parse" | "mpegtsmux" | "aacparse" => match distro.as_deref() { "h264parse" | "mpegtsmux" | "aacparse" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugins-bad", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugins-bad"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-plugins-bad",
Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free", Some("fedora" | "nobara") => "gstreamer1-plugins-bad-free",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-bad",
_ => "the GStreamer plugins-bad set", _ => "the GStreamer plugins-bad set",
}, },
"pulsesrc" => match distro.as_deref() { "pulsesrc" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-plugins-good", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-plugins-good"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pulseaudio", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-pulseaudio",
Some("fedora" | "nobara") => "gstreamer1-plugins-good", Some("fedora" | "nobara") => "gstreamer1-plugins-good",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-plugins-good",
_ => "the GStreamer PulseAudio plugin", _ => "the GStreamer PulseAudio plugin",
}, },
"avenc_aac" => match distro.as_deref() { "avenc_aac" => match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => "gst-libav", Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
"gst-libav"
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-libav", Some("debian" | "ubuntu" | "pop" | "linuxmint") => "gstreamer1.0-libav",
Some("fedora" | "nobara") => "gstreamer1-libav", Some("fedora" | "nobara") => "gstreamer1-libav",
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-libav", Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => "gstreamer-libav",
@@ -175,10 +197,14 @@ fn install_hint_for_gst_element(name: &str) -> String {
fn install_command(distro: &Option<String>, pkg: &str) -> String { fn install_command(distro: &Option<String>, pkg: &str) -> String {
let cmd = match distro.as_deref() { let cmd = match distro.as_deref() {
Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => format!("sudo pacman -S {pkg}"), Some("arch" | "cachyos" | "manjaro" | "endeavouros" | "artix" | "garuda") => {
format!("sudo pacman -S {pkg}")
}
Some("debian" | "ubuntu" | "pop" | "linuxmint") => format!("sudo apt install {pkg}"), Some("debian" | "ubuntu" | "pop" | "linuxmint") => format!("sudo apt install {pkg}"),
Some("fedora" | "nobara") => format!("sudo dnf install {pkg}"), Some("fedora" | "nobara") => format!("sudo dnf install {pkg}"),
Some("opensuse" | "opensuse-tumbleweed" | "opensuse-leap") => format!("sudo zypper 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 the `{pkg}` package via your distro's package manager"),
}; };
format!("Install hint: {cmd}") format!("Install hint: {cmd}")
+12 -4
View File
@@ -261,12 +261,20 @@ mod tests {
#[test] #[test]
fn capture_state_round_trips() { fn capture_state_round_trips() {
assert!(matches!( assert!(matches!(
parse(Event::Capture { state: EmitState::Started }), parse(Event::Capture {
ChildEvent::Capture { state: CaptureState::Started } state: EmitState::Started
}),
ChildEvent::Capture {
state: CaptureState::Started
}
)); ));
assert!(matches!( assert!(matches!(
parse(Event::Capture { state: EmitState::Stopped }), parse(Event::Capture {
ChildEvent::Capture { state: CaptureState::Stopped } state: EmitState::Stopped
}),
ChildEvent::Capture {
state: CaptureState::Stopped
}
)); ));
} }
+23 -19
View File
@@ -52,9 +52,8 @@ impl Routing {
let pid = std::process::id(); let pid = std::process::id();
let sink_name = format!("pixelpass_capture_{pid}"); let sink_name = format!("pixelpass_capture_{pid}");
let sink_module = let sink_module = load_module(&["module-null-sink", &format!("sink_name={sink_name}")])
load_module(&["module-null-sink", &format!("sink_name={sink_name}")]) .context("failed to load module-null-sink")?;
.context("failed to load module-null-sink")?;
// 20ms loopback latency keeps the mirrored audio tight; pactl's // 20ms loopback latency keeps the mirrored audio tight; pactl's
// default of 200ms is enough to be perceptible. // default of 200ms is enough to be perceptible.
@@ -205,7 +204,9 @@ fn parse_sink_inputs(stdout: &[u8]) -> Result<Vec<App>> {
serde_json::from_slice(stdout).context("pactl returned unparseable JSON")?; serde_json::from_slice(stdout).context("pactl returned unparseable JSON")?;
let mut counts: BTreeMap<String, u32> = BTreeMap::new(); let mut counts: BTreeMap<String, u32> = BTreeMap::new();
for entry in entries { for entry in entries {
let Some(name) = entry.properties.application_name else { continue }; let Some(name) = entry.properties.application_name else {
continue;
};
let trimmed = name.trim(); let trimmed = name.trim();
if trimmed.is_empty() { if trimmed.is_empty() {
continue; continue;
@@ -359,16 +360,14 @@ fn run_router(
) -> Result<()> { ) -> Result<()> {
use pipewire::{self as pw, types::ObjectType}; use pipewire::{self as pw, types::ObjectType};
let main_loop = pw::main_loop::MainLoopRc::new(None) let main_loop =
.context("pw main loop construction failed")?; pw::main_loop::MainLoopRc::new(None).context("pw main loop construction failed")?;
let context = pw::context::ContextRc::new(&main_loop, None) let context =
.context("pw context construction failed")?; pw::context::ContextRc::new(&main_loop, None).context("pw context construction failed")?;
let core = context let core = context
.connect_rc(None) .connect_rc(None)
.context("pw core connect failed (is the daemon running?)")?; .context("pw core connect failed (is the daemon running?)")?;
let registry = core let registry = core.get_registry_rc().context("pw get_registry failed")?;
.get_registry_rc()
.context("pw get_registry failed")?;
let state = Rc::new(RefCell::new(RouterState { let state = Rc::new(RefCell::new(RouterState {
sink_serial: None, sink_serial: None,
@@ -409,20 +408,21 @@ fn run_router(
let _reg_listener = registry let _reg_listener = registry
.add_listener_local() .add_listener_local()
.global(move |obj| { .global(move |obj| {
let Some(reg) = registry_weak.upgrade() else { return }; let Some(reg) = registry_weak.upgrade() else {
return;
};
match obj.type_ { match obj.type_ {
ObjectType::Node => { ObjectType::Node => {
let Some(props) = obj.props.as_ref() else { return }; let Some(props) = obj.props.as_ref() else {
return;
};
if props.get("node.name") == Some(sink_name_owned.as_str()) { if props.get("node.name") == Some(sink_name_owned.as_str()) {
if let Some(serial) = props if let Some(serial) = props
.get("object.serial") .get("object.serial")
.and_then(|s| s.parse::<u32>().ok()) .and_then(|s| s.parse::<u32>().ok())
{ {
state_for_reg.borrow_mut().sink_serial = Some(serial); state_for_reg.borrow_mut().sink_serial = Some(serial);
tracing::info!( tracing::info!(serial, "audio routing: pixelpass sink registered");
serial,
"audio routing: pixelpass sink registered"
);
try_flush(&state_for_reg, &event_tx_for_reg); try_flush(&state_for_reg, &event_tx_for_reg);
} }
return; return;
@@ -430,7 +430,9 @@ fn run_router(
if props.get("media.class") != Some("Stream/Output/Audio") { if props.get("media.class") != Some("Stream/Output/Audio") {
return; return;
} }
let Some(app) = props.get("application.name") else { return }; let Some(app) = props.get("application.name") else {
return;
};
if !app.eq_ignore_ascii_case(&filter_lower) { if !app.eq_ignore_ascii_case(&filter_lower) {
return; return;
} }
@@ -443,7 +445,9 @@ fn run_router(
try_flush(&state_for_reg, &event_tx_for_reg); try_flush(&state_for_reg, &event_tx_for_reg);
} }
ObjectType::Metadata => { ObjectType::Metadata => {
let Some(props) = obj.props.as_ref() else { return }; let Some(props) = obj.props.as_ref() else {
return;
};
if props.get("metadata.name") != Some("default") { if props.get("metadata.name") != Some("default") {
return; return;
} }
+34 -7
View File
@@ -256,7 +256,9 @@ fn spawn_kick_listener(sup_tx: mpsc::Sender<SupervisorMsg>) {
let Some(id) = line.trim().strip_prefix("kick ") else { let Some(id) = line.trim().strip_prefix("kick ") else {
continue; continue;
}; };
let msg = SupervisorMsg::KickViewer { id: id.trim().to_string() }; let msg = SupervisorMsg::KickViewer {
id: id.trim().to_string(),
};
// blocking_send is valid here: this is a plain thread, not inside // blocking_send is valid here: this is a plain thread, not inside
// the tokio runtime. An Err means the supervisor closed — stop. // the tokio runtime. An Err means the supervisor closed — stop.
if sup_tx.blocking_send(msg).is_err() { if sup_tx.blocking_send(msg).is_err() {
@@ -315,7 +317,11 @@ async fn supervise(
viewers.insert(id.clone(), cancel); viewers.insert(id.clone(), cancel);
let active = viewers.len() as u32; let active = viewers.len() as u32;
let _ = reply.send(Ok(port)); let _ = reply.send(Ok(port));
output::emit(output::Event::ViewerJoined { id: &id, active, max: max_viewers }); output::emit(output::Event::ViewerJoined {
id: &id,
active,
max: max_viewers,
});
tracing::info!(active, cap = max_viewers, "viewer joined"); tracing::info!(active, cap = max_viewers, "viewer joined");
} }
SupervisorMsg::RemoveViewer { id } => { SupervisorMsg::RemoveViewer { id } => {
@@ -325,7 +331,11 @@ async fn supervise(
continue; continue;
} }
let active = viewers.len() as u32; let active = viewers.len() as u32;
output::emit(output::Event::ViewerLeft { id: &id, active, max: max_viewers }); output::emit(output::Event::ViewerLeft {
id: &id,
active,
max: max_viewers,
});
tracing::info!(active, cap = max_viewers, "viewer left"); tracing::info!(active, cap = max_viewers, "viewer left");
if active == 0 if active == 0
&& let Some(h) = handle.take() && let Some(h) = handle.take()
@@ -372,10 +382,25 @@ fn print_host_banner(
eprintln!("┌─ PixelPass · host ─────────────────────────────────────────"); eprintln!("┌─ PixelPass · host ─────────────────────────────────────────");
eprintln!("│ display server : {display:?}"); eprintln!("│ display server : {display:?}");
eprintln!("│ capture : {}", capture_summary(opts)); eprintln!("│ capture : {}", capture_summary(opts));
eprintln!("│ quality : {}{}", quality.label, quality.dimensions_summary()); eprintln!(
"│ quality : {} — {}",
quality.label,
quality.dimensions_summary()
);
eprintln!("│ ({})", quality.note); eprintln!("│ ({})", quality.note);
eprintln!("│ hw encode : {}", if opts.no_hwencode { "off (software x264)" } else { "on (VAAPI H.264)" }); eprintln!(
eprintln!("│ max viewers : {} ({})", resolution.value, resolution.source.label()); "│ hw encode : {}",
if opts.no_hwencode {
"off (software x264)"
} else {
"on (VAAPI H.264)"
}
);
eprintln!(
"│ max viewers : {} ({})",
resolution.value,
resolution.source.label()
);
eprintln!(""); eprintln!("");
if clipboard_ok { if clipboard_ok {
eprintln!("│ Your share code has been copied to your clipboard."); eprintln!("│ Your share code has been copied to your clipboard.");
@@ -439,7 +464,9 @@ fn resolve_max_viewers(opts: &HostOpts, effective_bitrate: u32) -> MaxViewersRes
let n = bandwidth::recommended_max_viewers(upstream, effective_bitrate); let n = bandwidth::recommended_max_viewers(upstream, effective_bitrate);
return MaxViewersResolution { return MaxViewersResolution {
value: n, value: n,
source: MaxViewersSource::BandwidthMeasurement { safe_mbps: upstream }, source: MaxViewersSource::BandwidthMeasurement {
safe_mbps: upstream,
},
}; };
} }
MaxViewersResolution { MaxViewersResolution {
+3 -1
View File
@@ -308,7 +308,9 @@ async fn default_audio_monitor() -> Result<String> {
.arg("get-default-sink") .arg("get-default-sink")
.output() .output()
.await .await
.context("failed to run `pactl get-default-sink` (install pulseaudio-utils or pipewire-pulse)")?; .context(
"failed to run `pactl get-default-sink` (install pulseaudio-utils or pipewire-pulse)",
)?;
if !output.status.success() { if !output.status.success() {
bail!( bail!(
"pactl get-default-sink failed: {}", "pactl get-default-sink failed: {}",
+31 -7
View File
@@ -27,10 +27,26 @@ impl Quality {
/// values and resolves to one of the others at runtime (see [`resolve_auto`]). /// values and resolves to one of the others at runtime (see [`resolve_auto`]).
fn preset(self) -> Option<Preset> { fn preset(self) -> Option<Preset> {
let p = match self { let p = match self {
Quality::Source => Preset { max_height: None, bitrate: 6000, framerate: 30 }, Quality::Source => Preset {
Quality::High => Preset { max_height: Some(1080), bitrate: 4000, framerate: 30 }, max_height: None,
Quality::Medium => Preset { max_height: Some(720), bitrate: 2500, framerate: 30 }, bitrate: 6000,
Quality::Low => Preset { max_height: Some(480), bitrate: 1000, framerate: 30 }, framerate: 30,
},
Quality::High => Preset {
max_height: Some(1080),
bitrate: 4000,
framerate: 30,
},
Quality::Medium => Preset {
max_height: Some(720),
bitrate: 2500,
framerate: 30,
},
Quality::Low => Preset {
max_height: Some(480),
bitrate: 1000,
framerate: 30,
},
Quality::Auto => return None, Quality::Auto => return None,
}; };
Some(p) Some(p)
@@ -49,7 +65,12 @@ impl Quality {
/// Fixed presets in descending quality order — Auto walks this to find the /// Fixed presets in descending quality order — Auto walks this to find the
/// best one whose per-viewer bitrate fits the measured upstream budget. /// best one whose per-viewer bitrate fits the measured upstream budget.
const AUTO_LADDER: [Quality; 4] = [Quality::Source, Quality::High, Quality::Medium, Quality::Low]; const AUTO_LADDER: [Quality; 4] = [
Quality::Source,
Quality::High,
Quality::Medium,
Quality::Low,
];
/// Auto's fallback when there is no usable bandwidth measurement. /// Auto's fallback when there is no usable bandwidth measurement.
const AUTO_FALLBACK: Quality = Quality::Medium; const AUTO_FALLBACK: Quality = Quality::Medium;
@@ -146,7 +167,9 @@ fn resolve_auto(safe_mbps: Option<f64>, sizing_viewers: u32) -> (Preset, String,
( (
preset, preset,
format!("Auto → {}", chosen.name()), format!("Auto → {}", chosen.name()),
format!("auto: {safe_mbps:.1} Mbps safe ÷ {n} viewer(s) = {budget_mbps:.1} Mbps each"), format!(
"auto: {safe_mbps:.1} Mbps safe ÷ {n} viewer(s) = {budget_mbps:.1} Mbps each"
),
) )
} }
None => { None => {
@@ -154,7 +177,8 @@ fn resolve_auto(safe_mbps: Option<f64>, sizing_viewers: u32) -> (Preset, String,
( (
preset, preset,
format!("Auto → {}", AUTO_FALLBACK.name()), format!("Auto → {}", AUTO_FALLBACK.name()),
"auto fallback — no bandwidth measurement (run `pixelpass --reconfigure`)".to_string(), "auto fallback — no bandwidth measurement (run `pixelpass --reconfigure`)"
.to_string(),
) )
} }
} }
+15 -5
View File
@@ -26,7 +26,11 @@ pub async fn start(opts: &HostOpts, quality: &EffectiveQuality) -> Result<Captur
.context("could not reach the xdg-desktop-portal ScreenCast interface")?; .context("could not reach the xdg-desktop-portal ScreenCast interface")?;
let session = proxy.create_session().await?; let session = proxy.create_session().await?;
let source = if opts.window { SourceType::Window } else { SourceType::Monitor }; let source = if opts.window {
SourceType::Window
} else {
SourceType::Monitor
};
proxy proxy
.select_sources( .select_sources(
&session, &session,
@@ -70,10 +74,16 @@ pub async fn start(opts: &HostOpts, quality: &EffectiveQuality) -> Result<Captur
"do-timestamp=true".to_string(), "do-timestamp=true".to_string(),
]; ];
pipeline::spawn(opts, quality, Some((w as u32, h as u32)), source_args, move || { pipeline::spawn(
// Parent no longer needs the pipewire fd — gst inherited its own copy. opts,
let _ = close(raw_fd); quality,
}) Some((w as u32, h as u32)),
source_args,
move || {
// Parent no longer needs the pipewire fd — gst inherited its own copy.
let _ = close(raw_fd);
},
)
.await .await
} }
+6 -5
View File
@@ -180,10 +180,7 @@ async fn preflight_if_needed(theme: &ColorfulTheme) {
eprintln!(); eprintln!();
let Ok(choice) = Select::with_theme(theme) let Ok(choice) = Select::with_theme(theme)
.with_prompt("Last bandwidth test failed. Try again?") .with_prompt("Last bandwidth test failed. Try again?")
.items([ .items(["Yes — retry now", "No — use the conservative default"])
"Yes — retry now",
"No — use the conservative default",
])
.default(0) .default(0)
.interact() .interact()
else { else {
@@ -344,5 +341,9 @@ pub fn prompt_player() -> Result<Player> {
.items(["mpv", "VLC"]) .items(["mpv", "VLC"])
.default(0) .default(0)
.interact()?; .interact()?;
Ok(if choice == 0 { Player::Mpv } else { Player::Vlc }) Ok(if choice == 0 {
Player::Mpv
} else {
Player::Vlc
})
} }
+5 -1
View File
@@ -73,7 +73,11 @@ async fn main() -> Result<()> {
} }
fn init_tracing(verbose: bool) { fn init_tracing(verbose: bool) {
let default = if verbose { "pixelpass=trace,iroh=info" } else { "pixelpass=info,iroh=warn" }; let default = if verbose {
"pixelpass=trace,iroh=info"
} else {
"pixelpass=info,iroh=warn"
};
let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default)); let filter = EnvFilter::try_from_default_env().unwrap_or_else(|_| EnvFilter::new(default));
// Tracing MUST write to stderr. `tracing_subscriber::fmt()` defaults its // Tracing MUST write to stderr. `tracing_subscriber::fmt()` defaults its
// writer to stdout, but with `--output json` stdout carries the JSON event // writer to stdout, but with `--output json` stdout carries the JSON event
+4 -4
View File
@@ -110,9 +110,7 @@ pub async fn run() -> Result<()> {
} }
if live_skipped > 0 { if live_skipped > 0 {
println!( println!("[pixelpass] --repair: left {live_skipped} live pixelpass host(s) alone.");
"[pixelpass] --repair: left {live_skipped} live pixelpass host(s) alone."
);
} }
if failed > 0 { if failed > 0 {
@@ -154,7 +152,9 @@ fn list_modules() -> Result<Vec<Module>> {
for line in text.lines() { for line in text.lines() {
let mut parts = line.splitn(4, '\t'); let mut parts = line.splitn(4, '\t');
let Some(id_str) = parts.next() else { continue }; let Some(id_str) = parts.next() else { continue };
let Ok(id) = id_str.parse::<u32>() else { continue }; let Ok(id) = id_str.parse::<u32>() else {
continue;
};
let Some(name) = parts.next() else { continue }; let Some(name) = parts.next() else { continue };
let args = parts.next().unwrap_or("").to_string(); let args = parts.next().unwrap_or("").to_string();
modules.push(Module { modules.push(Module {