feat: Implement QuickLZ decompression, fragment reassembly, and voice echo

This commit is contained in:
Jose Luis Montañes Ojados
2026-01-15 17:14:39 +01:00
parent 8d98579faa
commit 7a9844f977
2 changed files with 45 additions and 18 deletions

View File

@@ -576,31 +576,57 @@ func (c *Client) getCryptoState() (key, nonce, mac []byte, isHandshake bool) {
// This starts AFTER clientek? Or WITH clientek? "clientek already has the packet id 1" // This starts AFTER clientek? Or WITH clientek? "clientek already has the packet id 1"
func (c *Client) handleVoice(pkt *protocol.Packet) { func (c *Client) handleVoice(pkt *protocol.Packet) {
// Parse Voice Header // Parse Voice Header (Server -> Client)
// 2 bytes VID, 1 byte Codec, Data // VID(2) + CID(2) + Codec(1) + Data
if len(pkt.Data) < 3 { if len(pkt.Data) < 5 {
return return
} }
// vid := binary.BigEndian.Uint16(pkt.Data[0:2]) vid := binary.BigEndian.Uint16(pkt.Data[0:2])
// codec := pkt.Data[2] // cid := binary.BigEndian.Uint16(pkt.Data[2:4]) // Talking client ID (not needed for echo)
voiceData := pkt.Data[3:] codec := pkt.Data[4]
voiceData := pkt.Data[5:]
// Calculate "Volume" (RMS of encrypted/compressed data is meaningless, but existing requirement asks for it) log.Printf("Voice Packet received. VID=%d, Codec=%d, Size=%d", vid, codec, len(voiceData))
// To do this properly, we need to decrypt -> decode[Opus] -> PCM -> RMS.
// For "Eco" (Echo), we can just re-wrap this data and send it back.
vol := len(voiceData) // Placeholder "volume" // Build echo packet (Client -> Server)
log.Printf("Voice Packet received. Approx Size/Vol: %d", vol) // Format: VID(2) + Codec(1) + Data
echoData := make([]byte, 2+1+len(voiceData))
binary.BigEndian.PutUint16(echoData[0:2], vid)
echoData[2] = codec
copy(echoData[3:], voiceData)
// Echo back echoPkt := protocol.NewPacket(protocol.PacketTypeVoice, echoData)
// Client -> Server Voice Packet echoPkt.Header.PacketID = pkt.Header.PacketID // Use same ID for voice
// VID + Codec + Data echoPkt.Header.ClientID = c.ClientID
// We can reuse the data payload structure mostly?
// C->S: VID(2) + Codec(1) + Data // Encrypt voice packet with SharedSecret
if c.Handshake != nil && len(c.Handshake.SharedIV) > 0 {
crypto := &protocol.CryptoState{
SharedIV: c.Handshake.SharedIV,
SharedMac: c.Handshake.SharedMac,
GenerationID: 0,
}
key, nonce := crypto.GenerateKeyNonce(&echoPkt.Header, true)
// Meta for Client->Server: PID(2) + CID(2) + PT(1)
meta := make([]byte, 5)
binary.BigEndian.PutUint16(meta[0:2], echoPkt.Header.PacketID)
binary.BigEndian.PutUint16(meta[2:4], echoPkt.Header.ClientID)
meta[4] = echoPkt.Header.Type
encData, mac, err := protocol.EncryptEAX(key, nonce, meta, echoPkt.Data)
if err != nil {
log.Printf("Voice encryption failed: %v", err)
return
}
echoPkt.Data = encData
copy(echoPkt.Header.MAC[:], mac)
} else {
// If no encryption keys, use SharedMac
echoPkt.Header.MAC = protocol.HandshakeMac
}
echoPkt := protocol.NewPacket(protocol.PacketTypeVoice, pkt.Data)
// ID Counter handling?
c.Conn.SendPacket(echoPkt) c.Conn.SendPacket(echoPkt)
} }

1
tsdeclarations Submodule

Submodule tsdeclarations added at fb4e50d643