Improve error warnings and command behavior for vmic
- Updated `vmic route` to use "none" instead of "off" for source removal, standardizing terminology. - Added warnings for handling stale `pw-loopback` processes during `vmic edit` operations. - Enhanced logging for `vmic route` to provide detailed feedback on moved streams. - Ensured stable sorting of ports in PipeWire graph for consistent behavior.
This commit is contained in:
@@ -60,8 +60,8 @@ pub struct RouteArgs {
|
||||
#[arg(short, long = "output", value_name = "APP[:MEDIA]")]
|
||||
pub outputs: Vec<String>,
|
||||
|
||||
/// Mix a hardware source into the vmic, or "off" to remove it.
|
||||
#[arg(short, long = "source", value_name = "SOURCE|off")]
|
||||
/// Mix a hardware source into the vmic, or "none" to remove it.
|
||||
#[arg(short, long = "source", value_name = "SOURCE|none")]
|
||||
pub source: Option<String>,
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ pub fn run(args: EditArgs) -> Result<()> {
|
||||
let name = state::normalize(&args.name);
|
||||
let mut state = VmicState::load(&conn, &name)?;
|
||||
let graph = PwGraph::connect()?;
|
||||
warn_if_stale(&graph, &state);
|
||||
|
||||
if let Some(enable) = args.loopback {
|
||||
edit_loopback(&graph, &mut state, enable)?;
|
||||
@@ -30,6 +31,23 @@ pub fn run(args: EditArgs) -> Result<()> {
|
||||
state.save(&conn)
|
||||
}
|
||||
|
||||
/// Warns if the tracked pw-loopback processes aren't visible in the live
|
||||
/// graph, so changes made below may silently fail to apply.
|
||||
fn warn_if_stale(graph: &PwGraph, state: &VmicState) {
|
||||
let alive = |id: Option<u32>| id.is_some_and(|id| graph.nodes().iter().any(|n| n.id == id));
|
||||
if !alive(state.sink_node_id) {
|
||||
ui::warn(&format!(
|
||||
"vmic '{}' appears stale (matching pw-loopback process not found); changes may not apply!",
|
||||
state.name
|
||||
));
|
||||
} else if !alive(state.mix_node_id) {
|
||||
ui::warn(&format!(
|
||||
"vmic '{}' mix loopback process not found; -sv changes may not apply!",
|
||||
state.name
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn edit_loopback(graph: &PwGraph, state: &mut VmicState, enable: bool) -> Result<()> {
|
||||
match (enable, state.loopback_id) {
|
||||
(true, Some(id)) => {
|
||||
|
||||
@@ -44,12 +44,28 @@ fn move_stream(kind: &str, move_cmd: &str, target: &str, filter: &str) -> Result
|
||||
ui::warn(&format!("'{filter}': matched 0 streams, nothing moved."));
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut moved = 0;
|
||||
for m in &matches {
|
||||
std::process::Command::new("pactl")
|
||||
let status = std::process::Command::new("pactl")
|
||||
.args([move_cmd, &m.id, target])
|
||||
.status()?;
|
||||
if status.success() {
|
||||
moved += 1;
|
||||
}
|
||||
}
|
||||
|
||||
let total = matches.len();
|
||||
if moved == total {
|
||||
ui::info(&format!("'{filter}': matched {total} stream(s) -> moved to '{target}'."));
|
||||
} else if moved == 0 {
|
||||
ui::warn(&format!("'{filter}': matched {total} stream(s), but none could be moved to '{target}'."));
|
||||
} else {
|
||||
ui::warn(&format!(
|
||||
"'{filter}': matched {total} stream(s), moved {moved} to '{target}' ({} failed).",
|
||||
total - moved
|
||||
));
|
||||
}
|
||||
ui::info(&format!("'{filter}': matched {} stream(s) -> moved to '{target}'.", matches.len()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -165,7 +165,13 @@ impl PwGraph {
|
||||
let Some(node) = s.nodes.values().find(|n| n.name == node_name) else {
|
||||
return Vec::new();
|
||||
};
|
||||
s.ports.values().filter(|p| p.node_id == node.id).cloned().collect()
|
||||
// Ports come out of a HashMap, whose iteration order is randomized
|
||||
// per process - sort by id (assigned monotonically by PipeWire) so
|
||||
// callers that fall back to "first"/"second" port (see
|
||||
// `loopback::resolve_link_pairs`) get a stable, reproducible pick.
|
||||
let mut ports: Vec<Port> = s.ports.values().filter(|p| p.node_id == node.id).cloned().collect();
|
||||
ports.sort_by_key(|p| p.id);
|
||||
ports
|
||||
}
|
||||
|
||||
pub fn links(&self) -> Vec<Link> {
|
||||
|
||||
Reference in New Issue
Block a user