add config parser

This commit is contained in:
mii443
2024-02-13 15:01:50 +09:00
parent 56df294787
commit d8a7638775
8 changed files with 173 additions and 103 deletions

53
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -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
}

11
src/commands/device.rs Normal file
View File

@ -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()));
}
}

2
src/commands/mod.rs Normal file
View File

@ -0,0 +1,2 @@
pub mod device;
pub mod run;

33
src/commands/run.rs Normal file
View File

@ -0,0 +1,33 @@
use crate::args::Run;
fn reshape_audio_data<T>(input: &[T], channels: usize) -> Vec<Vec<T>>
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<T>(input: &[Vec<T>]) -> Vec<T>
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) {
}

52
src/config.rs Normal file
View File

@ -0,0 +1,52 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Serialize, Deserialize)]
struct RoutesConfig {
routes: Routes,
}
#[derive(Debug, Serialize, Deserialize)]
struct Routes {
input: Vec<Input>,
output: Vec<Output>,
}
#[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,
}

View File

@ -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<T>(input: &[T], channels: usize) -> Vec<Vec<T>>
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<T>(input: &[Vec<T>]) -> Vec<T>
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::<usize>().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::<Vec<f32>>();
match cli.command {
args::Commands::Run(run) => {
commands::run::run(run);
}
args::Commands::Device(device) => {
commands::device::device(device);
}
},
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);
}