send audio over native UDP with OCB2 encryption

Add the OCB2-AES128 crypt state used by the Mumble UDP channel.
CryptSetup carries the key and both nonces; the handler installs them
instead of being an unimplemented stub, so UDP audio can be encrypted
and decrypted at all.

Add the Mumble 1.5 native UDP transport.
The socket opens during the handshake so it is ready when CryptSetup
arrives, and audio is sent as a protobuf envelope with a leading type
byte. Advertise ourselves as a 1.5 client so servers select it.

Advance the decrypt IV from the server nonce.
Using the client nonce for inbound packets desynchronized the two
sides after the first packet.

Keep the legacy UDPVoiceOpus payload working inside 1.5 crypto.
A 1.5 server still tunnels the older 0x80 format to older peers, so
both payload shapes have to be decoded from the same envelope.

Fall back to the TCP tunnel until a UDP packet is authenticated.
Nothing confirms the return path works until the server answers, so
audio stays tunneled until then and switches to UDP afterwards.
Tunneled packets are ignored while UDP is active so a frame is never
processed twice.

Add -tcp to force the tunnel and skip UDP entirely.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Brandon McGinty
2026-08-20 14:24:44 -04:00
co-authored by Claude Opus 5
parent aa1d233c81
commit 3787ad4cd1
14 changed files with 2431 additions and 9 deletions
+2
View File
@@ -116,6 +116,7 @@ func main() {
buffers := flag.Int("buffers", 16, "number of audio buffers to use")
profile := flag.Bool("profile", false, "add http server to serve profiles")
noiseSuppressionEnabled := flag.Bool("noise-suppression", false, "enable noise suppression for microphone input")
tcpOnly := flag.Bool("tcp", false, "disable UDP, force audio through TCP tunnel")
logLevel := flag.String("log", "warn", "log level: debug, info, warn, error")
logFile := flag.String("logfile", "", "write logs to this file (logging is disabled when omitted)")
@@ -212,6 +213,7 @@ func main() {
NoiseSuppressor: noise.NewSuppressor(),
}
b.Config.Buffers = *buffers
b.Config.DisableUDP = *tcpOnly
b.Hotkeys = b.UserConfig.GetHotkeys()
b.UserConfig.SaveConfig()