mirror of
https://github.com/mii443/maudio-router.git
synced 2025-08-22 16:05:35 +00:00
add config parser
This commit is contained in:
53
Cargo.lock
generated
53
Cargo.lock
generated
@ -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"
|
||||
|
@ -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"
|
||||
|
28
src/args.rs
28
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
|
||||
}
|
11
src/commands/device.rs
Normal file
11
src/commands/device.rs
Normal 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
2
src/commands/mod.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub mod device;
|
||||
pub mod run;
|
33
src/commands/run.rs
Normal file
33
src/commands/run.rs
Normal 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
52
src/config.rs
Normal 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,
|
||||
}
|
95
src/main.rs
95
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<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>>();
|
||||
}
|
||||
},
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user