mirror of
https://github.com/haileys/bark
synced 2024-11-10 05:54:15 +00:00
allow configuring device and delay ms in config
This commit is contained in:
parent
e3f3918c15
commit
e73796150e
7 changed files with 148 additions and 2 deletions
24
Cargo.lock
generated
24
Cargo.lock
generated
|
@ -71,6 +71,7 @@ dependencies = [
|
|||
"nix 0.26.2",
|
||||
"rand",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"socket2",
|
||||
"static_assertions",
|
||||
"structopt",
|
||||
|
@ -352,6 +353,12 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.19.0"
|
||||
|
@ -793,6 +800,12 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.6"
|
||||
|
@ -834,6 +847,17 @@ dependencies = [
|
|||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.105"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_spanned"
|
||||
version = "0.6.3"
|
||||
|
|
|
@ -14,6 +14,7 @@ libc = "0.2.147"
|
|||
nix = { version = "0.26.2", features = ["time", "socket", "net", "poll", "user", "hostname"], default-features = false }
|
||||
rand = "0.8.5"
|
||||
serde = { version = "1.0.183", features = ["derive"] }
|
||||
serde_json = "1.0.105"
|
||||
socket2 = "0.5.3"
|
||||
static_assertions = "1.1.0"
|
||||
structopt = "0.3.26"
|
||||
|
|
81
src/audio.rs
Normal file
81
src/audio.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
use std::process::{Command, Stdio};
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
pub fn set_sink_env(device: &str) {
|
||||
let Some(index) = find_pulse_node(Kind::Sink, device) else {
|
||||
eprintln!("falling back to default audio sink");
|
||||
return;
|
||||
};
|
||||
|
||||
println!("using audio sink at index {}: {}", index.0, device);
|
||||
|
||||
std::env::set_var("PULSE_SINK", device);
|
||||
std::env::set_var("PIPEWIRE_NODE", index.0.to_string());
|
||||
}
|
||||
|
||||
pub fn set_source_env(device: &str) {
|
||||
let Some(index) = find_pulse_node(Kind::Source, device) else {
|
||||
eprintln!("falling back to default audio source");
|
||||
return;
|
||||
};
|
||||
|
||||
println!("using audio source at index {}: {}", index.0, device);
|
||||
|
||||
std::env::set_var("PULSE_SOURCE", device);
|
||||
std::env::set_var("PIPEWIRE_NODE", index.0.to_string());
|
||||
}
|
||||
|
||||
enum Kind {
|
||||
Source,
|
||||
Sink,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Node {
|
||||
index: NodeIndex,
|
||||
name: String,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct NodeIndex(u64);
|
||||
|
||||
fn find_pulse_node(kind: Kind, name: &str) -> Option<NodeIndex> {
|
||||
let kind = match kind {
|
||||
Kind::Source => "sources",
|
||||
Kind::Sink => "sinks",
|
||||
};
|
||||
|
||||
let result = Command::new("pactl")
|
||||
.args(["--format=json", "list", kind])
|
||||
.stdout(Stdio::piped())
|
||||
.output();
|
||||
|
||||
let output = match result {
|
||||
Ok(output) => output,
|
||||
Err(e) => {
|
||||
eprintln!("error running pactl to find audio device: {e:?}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let text = match std::str::from_utf8(&output.stdout) {
|
||||
Ok(text) => text,
|
||||
Err(e) => {
|
||||
eprintln!("could not parse pactl output: {e:?}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let nodes = match serde_json::from_str::<Vec<Node>>(text) {
|
||||
Ok(nodes) => nodes,
|
||||
Err(e) => {
|
||||
eprintln!("could not parse pactl output: {e:?}");
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
nodes.into_iter()
|
||||
.find(|node| node.name == name)
|
||||
.map(|node| node.index)
|
||||
}
|
|
@ -7,6 +7,21 @@ use serde::Deserialize;
|
|||
#[derive(Deserialize)]
|
||||
pub struct Config {
|
||||
multicast: Option<SocketAddr>,
|
||||
#[serde(default)]
|
||||
source: Source,
|
||||
#[serde(default)]
|
||||
receive: Receive,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Source {
|
||||
device: Option<String>,
|
||||
delay_ms: Option<u64>,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Default)]
|
||||
pub struct Receive {
|
||||
device: Option<String>,
|
||||
}
|
||||
|
||||
fn set_env_option<T: ToString>(name: &str, value: Option<T>) {
|
||||
|
@ -16,7 +31,10 @@ fn set_env_option<T: ToString>(name: &str, value: Option<T>) {
|
|||
}
|
||||
|
||||
pub fn load_into_env(config: &Config) {
|
||||
set_env_option("BARK_MULTICAST", config.multicast)
|
||||
set_env_option("BARK_MULTICAST", config.multicast);
|
||||
set_env_option("BARK_SOURCE_DEVICE", config.source.device.as_ref());
|
||||
set_env_option("BARK_SOURCE_DELAY_MS", config.source.delay_ms);
|
||||
set_env_option("BARK_RECEIVE_DEVICE", config.receive.device.as_ref());
|
||||
}
|
||||
|
||||
fn load_file(path: &Path) -> Option<Config> {
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
mod audio;
|
||||
mod config;
|
||||
mod protocol;
|
||||
mod receive;
|
||||
|
|
|
@ -472,6 +472,8 @@ impl<T: Copy + Default + Ord> Aggregate<T> {
|
|||
pub struct ReceiveOpt {
|
||||
#[structopt(flatten)]
|
||||
pub socket: SocketOpt,
|
||||
#[structopt(long, env = "BARK_RECEIVE_DEVICE")]
|
||||
pub device: Option<String>,
|
||||
#[structopt(long, default_value="12")]
|
||||
pub max_seq_gap: usize,
|
||||
}
|
||||
|
@ -480,6 +482,10 @@ pub fn run(opt: ReceiveOpt) -> Result<(), RunError> {
|
|||
let receiver_id = ReceiverId::generate();
|
||||
let node = NodeStats::get();
|
||||
|
||||
if let Some(device) = &opt.device {
|
||||
crate::audio::set_sink_env(device);
|
||||
}
|
||||
|
||||
let host = cpal::default_host();
|
||||
|
||||
let device = host.default_output_device()
|
||||
|
|
|
@ -18,13 +18,28 @@ use crate::RunError;
|
|||
pub struct StreamOpt {
|
||||
#[structopt(flatten)]
|
||||
pub socket: SocketOpt,
|
||||
#[structopt(long, default_value="20")]
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
env = "BARK_SOURCE_DEVICE",
|
||||
)]
|
||||
pub device: Option<String>,
|
||||
|
||||
#[structopt(
|
||||
long,
|
||||
env = "BARK_SOURCE_DELAY_MS",
|
||||
default_value = "20",
|
||||
)]
|
||||
pub delay_ms: u64,
|
||||
}
|
||||
|
||||
pub fn run(opt: StreamOpt) -> Result<(), RunError> {
|
||||
let host = cpal::default_host();
|
||||
|
||||
if let Some(device) = &opt.device {
|
||||
crate::audio::set_source_env(device);
|
||||
}
|
||||
|
||||
let device = host.default_input_device()
|
||||
.ok_or(RunError::NoDeviceAvailable)?;
|
||||
|
||||
|
|
Loading…
Reference in a new issue