E2E crypto handshake: - Client/relay handshake via SignalMessage (CallOffer/CallAnswer) - X25519 ephemeral key exchange with Ed25519 identity signatures - Integration tests proving bidirectional encrypt/decrypt Codec2 integration: - Pure Rust codec2 crate (v0.3) — no C bindings needed - MODE_3200 (160 samples/20ms, 8 bytes) and MODE_1200 (320 samples/40ms, 6 bytes) - 11 new tests including encode/decode roundtrip and adaptive switching Relay forwarding: - Bidirectional client → remote forwarding with pipeline processing - CLI args: --listen, --remote - Periodic stats logging, clean shutdown via tokio::select! Benchmark tool (wzp-bench): - Codec roundtrip, FEC recovery, crypto throughput, full pipeline benchmarks - Sine wave PCM generator for realistic testing Audio I/O (cpal): - AudioCapture (microphone) and AudioPlayback (speakers) at 48kHz mono - CLI --live mode: mic → encode → send / recv → decode → speakers 120 tests passing, 0 failures. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
153 lines
5.6 KiB
Rust
153 lines
5.6 KiB
Rust
//! WarzonePhone benchmark CLI.
|
|
//!
|
|
//! Usage: wzp-bench [--codec] [--fec] [--crypto] [--pipeline] [--all]
|
|
//! wzp-bench --fec --loss 30 (test FEC with 30% loss)
|
|
|
|
use wzp_client::bench;
|
|
|
|
fn print_header(title: &str) {
|
|
println!();
|
|
println!("┌─────────────────────────────────────────────────────┐");
|
|
println!("│ {:<51} │", title);
|
|
println!("├─────────────────────────────────────────────────────┤");
|
|
}
|
|
|
|
fn print_row(label: &str, value: &str) {
|
|
println!("│ {:<28} {:>20} │", label, value);
|
|
}
|
|
|
|
fn print_footer() {
|
|
println!("└─────────────────────────────────────────────────────┘");
|
|
}
|
|
|
|
fn run_codec() {
|
|
print_header("Codec Roundtrip (Opus 24kbps)");
|
|
let r = bench::bench_codec_roundtrip();
|
|
print_row("Frames", &format!("{}", r.frames));
|
|
print_row("Encode total", &format!("{:.2} ms", r.total_encode.as_secs_f64() * 1000.0));
|
|
print_row("Decode total", &format!("{:.2} ms", r.total_decode.as_secs_f64() * 1000.0));
|
|
print_row("Avg encode", &format!("{:.1} us", r.avg_encode_us));
|
|
print_row("Avg decode", &format!("{:.1} us", r.avg_decode_us));
|
|
print_row("Throughput", &format!("{:.0} frames/sec", r.frames_per_sec));
|
|
print_row("Compression ratio", &format!("{:.1}x", r.compression_ratio));
|
|
print_footer();
|
|
}
|
|
|
|
fn run_fec(loss_pct: f32) {
|
|
print_header(&format!("FEC Recovery (loss={:.0}%)", loss_pct));
|
|
let r = bench::bench_fec_recovery(loss_pct);
|
|
print_row("Blocks attempted", &format!("{}", r.blocks_attempted));
|
|
print_row("Blocks recovered", &format!("{}", r.blocks_recovered));
|
|
print_row("Recovery rate", &format!("{:.1}%", r.recovery_rate_pct));
|
|
print_row("Source bytes", &format!("{}", r.total_source_bytes));
|
|
print_row("Repair (overhead) bytes", &format!("{}", r.overhead_bytes));
|
|
print_row("Total time", &format!("{:.2} ms", r.total_time.as_secs_f64() * 1000.0));
|
|
print_footer();
|
|
}
|
|
|
|
fn run_crypto() {
|
|
print_header("Crypto (ChaCha20-Poly1305)");
|
|
let r = bench::bench_encrypt_decrypt();
|
|
print_row("Packets", &format!("{}", r.packets));
|
|
print_row("Total time", &format!("{:.2} ms", r.total_time.as_secs_f64() * 1000.0));
|
|
print_row("Throughput", &format!("{:.0} pkt/sec", r.packets_per_sec));
|
|
print_row("Bandwidth", &format!("{:.2} MB/sec", r.megabytes_per_sec));
|
|
print_row("Avg latency", &format!("{:.2} us", r.avg_latency_us));
|
|
print_footer();
|
|
}
|
|
|
|
fn run_pipeline() {
|
|
print_header("Full Pipeline (E2E)");
|
|
let r = bench::bench_full_pipeline();
|
|
print_row("Frames", &format!("{}", r.frames));
|
|
print_row("Encode pipeline", &format!("{:.2} ms", r.total_encode_pipeline.as_secs_f64() * 1000.0));
|
|
print_row("Decode pipeline", &format!("{:.2} ms", r.total_decode_pipeline.as_secs_f64() * 1000.0));
|
|
print_row("Avg E2E latency", &format!("{:.1} us/frame", r.avg_e2e_latency_us));
|
|
print_row("PCM in", &format!("{} bytes", r.pcm_bytes_in));
|
|
print_row("Wire out", &format!("{} bytes", r.wire_bytes_out));
|
|
print_row("Overhead ratio", &format!("{:.3}x", r.overhead_ratio));
|
|
print_footer();
|
|
}
|
|
|
|
fn print_usage() {
|
|
println!("Usage: wzp-bench [OPTIONS]");
|
|
println!();
|
|
println!("Options:");
|
|
println!(" --codec Run codec roundtrip benchmark");
|
|
println!(" --fec Run FEC recovery benchmark");
|
|
println!(" --crypto Run encryption benchmark");
|
|
println!(" --pipeline Run full pipeline benchmark");
|
|
println!(" --all Run all benchmarks (default)");
|
|
println!(" --loss <N> FEC loss percentage (default: 20)");
|
|
println!(" --help Show this help");
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<String> = std::env::args().skip(1).collect();
|
|
|
|
if args.iter().any(|a| a == "--help" || a == "-h") {
|
|
print_usage();
|
|
return;
|
|
}
|
|
|
|
let mut run_codec_flag = false;
|
|
let mut run_fec_flag = false;
|
|
let mut run_crypto_flag = false;
|
|
let mut run_pipeline_flag = false;
|
|
let mut loss_pct: f32 = 20.0;
|
|
|
|
let mut i = 0;
|
|
while i < args.len() {
|
|
match args[i].as_str() {
|
|
"--codec" => run_codec_flag = true,
|
|
"--fec" => run_fec_flag = true,
|
|
"--crypto" => run_crypto_flag = true,
|
|
"--pipeline" => run_pipeline_flag = true,
|
|
"--all" => {
|
|
run_codec_flag = true;
|
|
run_fec_flag = true;
|
|
run_crypto_flag = true;
|
|
run_pipeline_flag = true;
|
|
}
|
|
"--loss" => {
|
|
i += 1;
|
|
if i < args.len() {
|
|
loss_pct = args[i].parse().unwrap_or(20.0);
|
|
}
|
|
}
|
|
other => {
|
|
eprintln!("Unknown option: {}", other);
|
|
print_usage();
|
|
std::process::exit(1);
|
|
}
|
|
}
|
|
i += 1;
|
|
}
|
|
|
|
// Default: run all if no specific flag given
|
|
if !run_codec_flag && !run_fec_flag && !run_crypto_flag && !run_pipeline_flag {
|
|
run_codec_flag = true;
|
|
run_fec_flag = true;
|
|
run_crypto_flag = true;
|
|
run_pipeline_flag = true;
|
|
}
|
|
|
|
println!("=== WarzonePhone Protocol Benchmark ===");
|
|
|
|
if run_codec_flag {
|
|
run_codec();
|
|
}
|
|
if run_fec_flag {
|
|
run_fec(loss_pct);
|
|
}
|
|
if run_crypto_flag {
|
|
run_crypto();
|
|
}
|
|
if run_pipeline_flag {
|
|
run_pipeline();
|
|
}
|
|
|
|
println!();
|
|
println!("Done.");
|
|
}
|