Introduce initial implementation of the vmic CLI with PipeWire integration

- Added `Cargo.toml` to define dependencies and project metadata.
- Implemented core CLI functionality for managing virtual microphones (`create`, `edit`, `delete`, `list`, `route`, and `wipe` commands) using `clap`.
- Integrated `rusqlite` for persistent state storage and `pipewire` to manage PipeWire nodes.
- Ensured graceful handling of feedback loops and system defaults during virtual mic creation and deletion.
- Added error handling via `thiserror` for cleaner error definitions.
This commit is contained in:
2026-08-11 13:28:33 +02:00
parent 76c129a5dc
commit e19f398397
18 changed files with 2151 additions and 1 deletions

31
src/commands/delete.rs Normal file
View File

@@ -0,0 +1,31 @@
use crate::cli::DeleteArgs;
use crate::error::Result;
use crate::pw::{loopback, PwGraph};
use crate::state::{self, VmicState};
use crate::ui;
pub fn run(args: DeleteArgs) -> Result<()> {
let conn = state::open_db()?;
let name = state::normalize(&args.name);
let mut state = VmicState::load(&conn, &name)?;
let graph = PwGraph::connect()?;
if let Some(loopback_id) = state.loopback_id {
loopback::unload_pulse_module(loopback_id)?;
}
// Unlink a mixed-in hardware source explicitly; the links would also
// die with the nodes below.
super::unsource(&graph, &mut state)?;
if let Some(pid) = state.mix_pid {
loopback::terminate_stage(pid, &state.mix_name)?;
}
if let Some(pid) = state.sink_pid {
loopback::terminate_stage(pid, &state.sink_name)?;
}
VmicState::delete(&conn, &name)?;
ui::ok(&format!("Deleted virtual mic '{name}'."));
Ok(())
}