diff --git a/Cargo.lock b/Cargo.lock index 0f24e2b..ded7dfd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -370,6 +370,12 @@ dependencies = [ "either", ] +[[package]] +name = "itoa" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" + [[package]] name = "jni" version = "0.19.0" @@ -490,6 +496,8 @@ dependencies = [ "num", "num-traits", "rustfft", + "serde", + "serde_yaml", ] [[package]] @@ -908,6 +916,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + [[package]] name = "same-file" version = "1.0.6" @@ -923,6 +937,39 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_yaml" +version = "0.9.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adf8a49373e98a4c5f0ceb5d05aa7c648d75f63774981ed95b7c7443bbd50c6e" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + [[package]] name = "shlex" version = "1.3.0" @@ -1022,6 +1069,12 @@ version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +[[package]] +name = "unsafe-libyaml" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4c90930b95a82d00dc9e9ac071b4991924390d46cbd0dfe566148667605e4b" + [[package]] name = "utf8parse" version = "0.2.1" diff --git a/Cargo.toml b/Cargo.toml index b748a28..4900cd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,3 +11,5 @@ cpal = { git = "https://github.com/RustAudio/cpal.git", features = ["asio"] } num = "0.4.1" num-traits = "0.2.18" rustfft = "6.2.0" +serde = { version = "1.0.196", features = ["derive"] } +serde_yaml = "0.9.31" diff --git a/src/args.rs b/src/args.rs index 5343a91..d4915ee 100644 --- a/src/args.rs +++ b/src/args.rs @@ -6,33 +6,25 @@ use clap::{Args, Parser, Subcommand}; #[command(about = "A network audio router.", long_about = None)] pub struct Cli { #[command(subcommand)] - command: Commands, + pub command: Commands, } #[derive(Subcommand, Debug)] -enum Commands { - /// Run router server - Server(Server), - /// Run router client - Client(Client), +pub enum Commands { + /// Run router + Run(Run), + /// Device utilities + Device(Device), } #[derive(Args, Debug)] -struct Server { +pub struct Run { #[arg(short, long)] - device: String, - #[arg(short, long)] - listen_address: String, - #[arg(short, long)] - port: String, + pub config: String, } #[derive(Args, Debug)] -struct Client { +pub struct Device { #[arg(short, long)] - server_ip: String, - #[arg(short, long)] - port: String, - #[arg(short, long)] - device: String, + pub list: bool } \ No newline at end of file diff --git a/src/commands/device.rs b/src/commands/device.rs new file mode 100644 index 0000000..f3261bf --- /dev/null +++ b/src/commands/device.rs @@ -0,0 +1,11 @@ +use cpal::traits::{DeviceTrait, HostTrait}; + +use crate::args::Device; + +pub fn device(device: Device) { + let host = cpal::default_host(); + + if device.list { + host.input_devices().unwrap().enumerate().for_each(|(i, device)| println!("{}: {}", i, device.name().unwrap())); + } +} \ No newline at end of file diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..fea7f37 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,2 @@ +pub mod device; +pub mod run; \ No newline at end of file diff --git a/src/commands/run.rs b/src/commands/run.rs new file mode 100644 index 0000000..6b680f8 --- /dev/null +++ b/src/commands/run.rs @@ -0,0 +1,33 @@ +use crate::args::Run; + +fn reshape_audio_data(input: &[T], channels: usize) -> Vec> +where + T: Clone, +{ + let mut output = vec![vec![]; channels]; + for frame in input.chunks(channels) { + for (i, sample) in frame.iter().enumerate() { + output[i].push(sample.clone()); + } + } + output +} + +fn to_flat_audio_data(input: &[Vec]) -> Vec +where + T: Clone, +{ + let channels = input.len(); + let frames = input[0].len(); + let mut output = vec![]; + for i in 0..frames { + for j in 0..channels { + output.push(input[j][i].clone()); + } + } + output +} + +pub fn run(args: Run) { + +} \ No newline at end of file diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..099eada --- /dev/null +++ b/src/config.rs @@ -0,0 +1,52 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Debug, Serialize, Deserialize)] +struct RoutesConfig { + routes: Routes, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Routes { + input: Vec, + output: Vec, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Input { + name: String, + virtual_device: String, + device: Device, +} + +#[derive(Debug, Serialize, Deserialize)] +struct Output { + name: String, + input: OutputInput, + device: Device, +} + +#[derive(Debug, Serialize, Deserialize)] +struct OutputInput { + virtual_device: String, +} + +#[derive(Debug, Serialize, Deserialize)] +#[serde(untagged)] +enum Device { + Local { local: LocalDevice }, + Remote { remote: RemoteDevice }, +} + +#[derive(Debug, Serialize, Deserialize)] +struct LocalDevice { + name: String, +} + +#[derive(Debug, Serialize, Deserialize)] +struct RemoteDevice { + address: String, + port: u16, + protocol: String, + buffer: usize, + channels: u8, +} diff --git a/src/main.rs b/src/main.rs index 21ffca3..9dc53fb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,95 +1,20 @@ mod args; - -use std::{io::Write, sync::{Arc, Mutex}}; +mod config; +mod commands; use clap::Parser; -use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; use crate::args::Cli; -fn reshape_audio_data(input: &[T], channels: usize) -> Vec> -where - T: Clone, -{ - let mut output = vec![vec![]; channels]; - for frame in input.chunks(channels) { - for (i, sample) in frame.iter().enumerate() { - output[i].push(sample.clone()); - } - } - output -} - -fn to_flat_audio_data(input: &[Vec]) -> Vec -where - T: Clone, -{ - let channels = input.len(); - let frames = input[0].len(); - let mut output = vec![]; - for i in 0..frames { - for j in 0..channels { - output.push(input[j][i].clone()); - } - } - output -} fn main() { let cli = Cli::parse(); - println!("{:?}", cli); - - let host = cpal::default_host(); - - std::thread::sleep(std::time::Duration::from_secs(1)); - - println!("Available input devices:"); - host.input_devices().unwrap().enumerate().for_each(|(i, device)| println!("{}: {}", i, device.name().unwrap())); - - print!("Select input device [0~{}]> ", host.input_devices().unwrap().count() - 1); - std::io::stdout().flush().unwrap(); - - let mut input = String::new(); - std::io::stdin().read_line(&mut input).unwrap(); - let input = input.trim().parse::().unwrap(); - - let device = host.input_devices().unwrap().nth(input).unwrap(); - - let audio_data = Arc::new(Mutex::new(vec![])); - - let input_stream = device.build_input_stream( - &device.default_input_config().unwrap().config(), - { - let audio_data = audio_data.clone(); - move |data: &[f32], _: &_| { - let audio_data = &mut *audio_data.lock().unwrap(); - *audio_data = data.iter().map(|d| d.clone()).collect::>(); - } - }, - move |err| eprintln!("error: {}", err), - None - ).unwrap(); - - let output_stream = device.build_output_stream( - &device.default_output_config().unwrap().config(), - { - let audio_data = audio_data.clone(); - move |data: &mut [f32], _: &cpal::OutputCallbackInfo| { - let audio_data = audio_data.lock().unwrap().clone(); - let audio_data = reshape_audio_data(&audio_data, 22); - - let audio_data = to_flat_audio_data(&audio_data); - data.copy_from_slice(&audio_data); - } - }, - move |err| eprintln!("error: {}", err), - None - ).unwrap(); - - input_stream.play().unwrap(); - output_stream.play().unwrap(); - - std::thread::sleep(std::time::Duration::from_secs(1000)); - drop(input_stream); - drop(output_stream); + match cli.command { + args::Commands::Run(run) => { + commands::run::run(run); + } + args::Commands::Device(device) => { + commands::device::device(device); + } + } }