# 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.