# Milestone 3: The First Voice Call (The Connection) **Goal:** Successfully transmit compressed voice data to the server and back. ### 1. Opus Encoder (`client_node/audio/codec.rs`) - [ ] **Dependencies:** Add `audiopus`. - [ ] **Initialization:** Create an `audiopus::coder::Encoder` with `48,000 Hz`, `Mono`, and `Application::Voip`. Set the bitrate dynamically or hardcode to `48,000 bps` for testing. - [ ] **Encoding Loop:** Take the 960-sample `f32` chunks from the DSP thread and call `encoder.encode_float()`. This will output a `&[u8]` payload of variable length. ### 2. UDP Transport & Formatting (`client_node/network/voice.rs`) - [ ] **Packet Assembly:** Construct the UDP binary packet. Byte 0-3: `SessionToken` (from TCP handshake). Byte 4-11: `SequenceNumber` (incremented every chunk). Byte 12-19: `Timestamp` (`u64`). Byte 20+: The Opus payload. - [ ] **Fuzz Testing:** Use `proptest` to aggressively throw random, garbage byte arrays at the UDP packet parser to guarantee it never panics. - [ ] **Socket Binding:** Use `tokio::net::UdpSocket::bind("0.0.0.0:0")`. - [ ] **Transmission:** Send the assembled binary packet to the server's UDP port at `127.0.0.1:8080`. ### 3. Server Echo Relay (`server_node/udp_relay.rs`) - [ ] **Socket Setup:** `tokio::net::UdpSocket::bind("0.0.0.0:8080")`. - [ ] **Validation Loop:** `recv_from` the socket. Parse the first 4 bytes as `u32`. Check the `DashMap` to ensure the `SessionToken` is valid. - [ ] **Echo Mode:** Temporarily, immediately `send_to` the exact same `&[u8]` buffer back to the originating client `SocketAddr` to test the round-trip. - [ ] **Zero-Byte Keep-Alives:** Implement client logic to send an empty 0-byte UDP packet every 5 seconds. Server strictly ignores them (used for NAT traversal). ### 4. Opus Decoder & Playback (`client_node/audio/playback.rs`) - [ ] **Receiving:** Client UDP socket receives the echoed packet. Extract the Opus payload bytes. - [ ] **Decoding:** Initialize `audiopus::coder::Decoder` (`48,000 Hz`, `Mono`). Call `decoder.decode_float()` to retrieve the 960 `f32` samples. - [ ] **Playback:** Push the 960 samples into a secondary `cpal` output ringbuffer (The Speaker thread). ### 5. TCP Auto-Reconnect & UDP Chaos Simulator - [ ] **Auto-Reconnect Logic:** Wrap the TCP connection logic in a `loop`. If the socket drops (`read` returns 0), `tokio::time::sleep(2s)` and attempt to reconnect. Send a `ReconnectRequest` with the existing `SessionToken` instead of a full `AuthRequest`. - [ ] **Chaos Simulator UI:** In the `egui` Developer Settings, add a slider for `Packet Loss %`. Intercept outgoing UDP packets in `voice.rs`; use `rand::thread_rng` to randomly drop packets based on the slider value before hitting the socket.