feat: Phase 2 — relay daemon and client library with integration pipelines

wzp-relay:
- RelayPipeline: ingest → FEC decode → jitter buffer → FEC encode → send
- SessionManager: tracks active calls, idle expiry
- RelayConfig: TOML-based configuration
- Binary: accepts QUIC connections, receives media packets

wzp-client:
- CallEncoder: mic PCM → Opus encode → FEC → MediaPackets
- CallDecoder: MediaPackets → FEC decode → jitter → Opus decode → PCM
- CLI binary: connects to relay, sends test silence frames

99 tests passing across all 7 crates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Siavash Sameni
2026-03-27 13:08:33 +04:00
parent 51e893590c
commit 43d7f70fe9
11 changed files with 1023 additions and 10 deletions

View File

@@ -0,0 +1,56 @@
//! WarzonePhone CLI test client.
//!
//! Usage: wzp-client <relay-addr>
//!
//! Connects to a relay and sends silence frames for testing.
use std::net::SocketAddr;
use tracing::{error, info};
use wzp_client::call::{CallConfig, CallEncoder};
use wzp_proto::MediaTransport;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
tracing_subscriber::fmt().init();
let relay_addr: SocketAddr = std::env::args()
.nth(1)
.unwrap_or_else(|| "127.0.0.1:4433".to_string())
.parse()?;
info!(%relay_addr, "WarzonePhone client connecting");
let client_config = wzp_transport::client_config();
let endpoint = wzp_transport::create_endpoint("0.0.0.0:0".parse()?, None)?;
let connection =
wzp_transport::connect(&endpoint, relay_addr, "localhost", client_config).await?;
info!("Connected to relay");
let transport = wzp_transport::QuinnTransport::new(connection);
let config = CallConfig::default();
let mut encoder = CallEncoder::new(&config);
let frame_duration = tokio::time::Duration::from_millis(20);
let pcm = vec![0i16; 960]; // 20ms @ 48kHz silence
for i in 0..250u32 {
let packets = encoder.encode_frame(&pcm)?;
for pkt in &packets {
if let Err(e) = transport.send_media(pkt).await {
error!("send error: {e}");
break;
}
}
if i % 50 == 0 {
info!(frame = i, packets = packets.len(), "sent");
}
tokio::time::sleep(frame_duration).await;
}
info!("Done, closing");
transport.close().await?;
Ok(())
}