Skip to content

Instantly share code, notes, and snippets.

@drozdziak1
Created August 22, 2018 08:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save drozdziak1/fc9ecac2b9b5404e36887ed584957432 to your computer and use it in GitHub Desktop.
Save drozdziak1/fc9ecac2b9b5404e36887ed584957432 to your computer and use it in GitHub Desktop.
#[macro_use]
extern crate failure;
#[macro_use]
extern crate log;
extern crate env_logger;
extern crate rosc;
extern crate rustyline;
use failure::Error;
use log::LevelFilter;
use rosc::{decoder, encoder, OscMessage, OscPacket, OscType};
use std::{env, net::UdpSocket, process, process::Command, thread::sleep, time::Duration};
static DEFAULT_JMM_BOOTSTRAP_DELAY: Duration = Duration::from_millis(300);
static DEFAULT_JMM_PORT: u16 = 61234;
fn make_jmm_osc_request(
sock: &mut UdpSocket,
path: &str,
args: Option<Vec<OscType>>,
) -> Result<OscPacket, Error> {
let packet = OscPacket::Message(OscMessage {
addr: path.to_owned(),
args: args,
});
sock.send(match &encoder::encode(&packet) {
Ok(buf) => buf,
Err(e) => bail!("{:?}", e), // TODO: Flimsy, A more robust error would be better
})?;
sock.set_read_timeout(Some(Duration::from_secs(1)))?;
let mut buf = vec![0u8; 200];
sock.recv(&mut buf)?;
let recv_packet = match decoder::decode(&buf) {
Ok(p) => p,
Err(e) => bail!("{:?}", e), // TODO: same here
};
debug!(
"Successfuly received and parsed an OSC packet: {:?}",
recv_packet
);
Ok(recv_packet)
}
fn main() {
match env::var("RUST_LOG") {
Ok(_) => env_logger::init(),
Err(_) => env_logger::Builder::new()
.filter_level(LevelFilter::Info)
.init(),
}
let jmm_bootstrap_delay = match env::var("JMM_BOOTSTRAP_DELAY_MS") {
Ok(n) => Duration::from_millis(n.parse::<u64>().unwrap()),
Err(_) => DEFAULT_JMM_BOOTSTRAP_DELAY,
};
let jmm_port = match env::var("JMM_PORT") {
Ok(n) => n.parse::<u16>().unwrap(),
Err(_) => DEFAULT_JMM_PORT,
};
info!("Starting...");
// The jackminimix instance we wrap
let mut jmm = match Command::new("jackminimix")
.args(&["-p", &format!("{}", jmm_port)])
//.stdout(Stdio::null())
.spawn()
{
Ok(chld) => {
info!(
"Spawned a jackminimix instance with process id {}",
chld.id()
);
chld
}
Err(e) => {
error!("Could not spawn jackminimix: {:?}", e);
process::exit(1);
}
};
sleep(Duration::from_millis(500)); // Sometimes jackminimix wouldn't open its socket in time
let mut sock = UdpSocket::bind("0.0.0.0:0").unwrap();
info!("Socket bound to {:?}", sock.local_addr().unwrap());
sock.connect(format!("0.0.0.0:{}", jmm_port)).unwrap();
info!("Socket connected to 0.0.0.0:{}", jmm_port);
match make_jmm_osc_request(&mut sock, "/ping", None).unwrap() {
OscPacket::Message(OscMessage {
addr: "/pong".to_owned(),
args: None,
}) => info!("JMM ping OK"),
_ => {
error!("Failed to ping the jackminimix instance. Try setting JMM_BOOTSTRAP_DELAY above {:?}?", jmm_bootstrap_delay);
process::exit(1);
}
};
let channel_count =
match make_jmm_osc_request(&mut sock, "/mixer/get_channel_count", None).unwrap() {
OscPacket::Message(msg) => match msg.args {
Some(list) => match list.as_slice() {
[OscType::Int(count)] => count.clone(),
_ => {
error!("Received an unrecognized argument list from channel output query");
process::exit(1);
}
},
None => {
error!("Received an empty argument list from channel count query");
process::exit(1);
}
},
OscPacket::Bundle(_) => {
error!("Received a bundle message from channel count query");
process::exit(1);
}
};
info!("JackMiniMix has {:?} channels", channel_count);
let mut rl = rustyline::Editor::<()>::new();
loop {
if let Ok(line) = rl.readline("(jmm) ") {
debug!("Line {:?} received", line);
let mut split = line.split_whitespace();
match split.nth(0) {
Some("ping") => {
let packet = make_jmm_osc_request(&mut sock, "/ping", None).unwrap();
info!("Ping response: {:?}", packet);
}
// Get volume for all channels
Some("get-all") => for ch_id in 1..=channel_count {},
// Set volume for all channels
Some("set-all") => {
let gain: f32 = match split.nth(0) {
Some(g) => match g.parse() {
Ok(val) => val,
Err(e) => {
error!("Could not parse {:?} as float: {:?}", g, e);
continue;
}
},
None => {
error!("Missing gain to set. Example: \"set-all -3.5\"");
continue;
}
};
debug!(
"Attempting to set gain {:.1}db on all {:?} channels",
gain, channel_count
);
}
Some(other) => error!("Unknown command {:?}", other),
None => {}
}
} else {
jmm.kill().unwrap();
debug!("Killed jackminimix with process id {}", jmm.id());
println!("Bye!");
process::exit(0);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment