Avoid debug logging induced UDP loss

This commit is contained in:
Brandon McGinty (chatgpt)
2026-08-12 17:38:04 -04:00
committed by Brandon McGinty
parent 4510c25350
commit 883f7250f5
3 changed files with 27 additions and 12 deletions
+4 -1
View File
@@ -59,7 +59,10 @@ func (c *Client) udpReadRoutine() {
return return
} }
packetCount++ packetCount++
if log.Enabled(log.LevelDebug) { // A synchronous log write for every UDP datagram can itself make the
// reader fall behind and lose voice packets. Keep enough samples to
// diagnose framing while avoiding work on the audio hot path.
if log.Enabled(log.LevelDebug) && (packetCount <= 3 || packetCount%1000 == 0) {
log.Debug("UDP recv #%d: %d bytes from %s hex=%s", log.Debug("UDP recv #%d: %d bytes from %s hex=%s",
packetCount, n, addr, hex.EncodeToString(buf[:n])) packetCount, n, addr, hex.EncodeToString(buf[:n]))
} }
+6
View File
@@ -639,8 +639,10 @@ func (c *Client) WriteAudioUDP15(format byte, target uint32, sequence int64, dat
return false, err return false, err
} }
if log.Enabled(log.LevelDebug) && (frameNum < 3 || frameNum%1000 == 0 || final) {
log.Debug("UDP15 send: frame=%d opus_len=%d enc_len=%d final=%v", log.Debug("UDP15 send: frame=%d opus_len=%d enc_len=%d final=%v",
frameNum, len(data), len(encrypted), final) frameNum, len(data), len(encrypted), final)
}
_, err = udpConn.Write(encrypted) _, err = udpConn.Write(encrypted)
if err != nil { if err != nil {
@@ -675,7 +677,9 @@ func (c *Client) HandleUDPPacket15(packet []byte, pktNum uint64) {
return return
} }
if log.Enabled(log.LevelDebug) && (pktNum <= 3 || pktNum%1000 == 0) {
log.Debug("UDP15 #%d: decrypt OK, plaintext_len=%d", pktNum, len(plaintext)) log.Debug("UDP15 #%d: decrypt OK, plaintext_len=%d", pktNum, len(plaintext))
}
c.markUDPActive() c.markUDPActive()
// Check type byte (0x00 = Audio, 0x01 = Ping) // Check type byte (0x00 = Audio, 0x01 = Ping)
@@ -841,7 +845,9 @@ func (c *Client) decodeAndDispatch(pktNum uint64, user *User, decoder AudioDecod
return return
} }
if log.Enabled(log.LevelDebug) && (pktNum <= 3 || pktNum%1000 == 0) {
log.Debug("UDP15 #%d: Opus OK for %s, pcm_samples=%d", pktNum, user.Name, len(pcm)) log.Debug("UDP15 #%d: Opus OK for %s, pcm_samples=%d", pktNum, user.Name, len(pcm))
}
user.audioSequence = frameNum user.audioSequence = frameNum
user.audioSequenceValid = true user.audioSequenceValid = true
user.audioFrameStep = audioFrameStep(len(pcm)) user.audioFrameStep = audioFrameStep(len(pcm))
+9 -3
View File
@@ -486,6 +486,7 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
var jitterBuf []*gumble.AudioPacket var jitterBuf []*gumble.AudioPacket
var jitterNextSeq int64 var jitterNextSeq int64
var jitterInit, jitterStarted bool var jitterInit, jitterStarted bool
var jitterDrainLogCounter, jitterAnomalyLogCounter int
// insertSorted inserts a packet into the jitter buffer sorted // insertSorted inserts a packet into the jitter buffer sorted
// by sequence number. // by sequence number.
@@ -563,7 +564,6 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
jitterStarted = true jitterStarted = true
// Drain all packets that are ready (in sequence order) // Drain all packets that are ready (in sequence order)
drainedCount := 0
for { for {
pkt := popNext() pkt := popNext()
if pkt == nil { if pkt == nil {
@@ -571,16 +571,22 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
if jitterBuf[0].Sequence < jitterNextSeq { if jitterBuf[0].Sequence < jitterNextSeq {
// Late or duplicate: discard so it doesn't // Late or duplicate: discard so it doesn't
// permanently block the drain loop. // permanently block the drain loop.
jitterAnomalyLogCounter++
if jitterAnomalyLogCounter <= 3 || jitterAnomalyLogCounter%1000 == 0 {
log.Debug("jitter: discarding late seq=%d for %s (next=%d buf=%d)", log.Debug("jitter: discarding late seq=%d for %s (next=%d buf=%d)",
jitterBuf[0].Sequence, e.User.Name, jitterNextSeq, len(jitterBuf)) jitterBuf[0].Sequence, e.User.Name, jitterNextSeq, len(jitterBuf))
}
jitterBuf = jitterBuf[1:] jitterBuf = jitterBuf[1:]
continue continue
} }
if jitterBuf[0].Sequence > jitterNextSeq { if jitterBuf[0].Sequence > jitterNextSeq {
// Gap in sequence: skip ahead so we don't // Gap in sequence: skip ahead so we don't
// wait forever for a lost packet. // wait forever for a lost packet.
jitterAnomalyLogCounter++
if jitterAnomalyLogCounter <= 3 || jitterAnomalyLogCounter%1000 == 0 {
log.Debug("jitter: seq gap for %s, skipping from %d to %d (buf=%d)", log.Debug("jitter: seq gap for %s, skipping from %d to %d (buf=%d)",
e.User.Name, jitterNextSeq, jitterBuf[0].Sequence, len(jitterBuf)) e.User.Name, jitterNextSeq, jitterBuf[0].Sequence, len(jitterBuf))
}
jitterNextSeq = jitterBuf[0].Sequence jitterNextSeq = jitterBuf[0].Sequence
continue continue
} }
@@ -589,8 +595,8 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
} }
break break
} }
drainedCount++ jitterDrainLogCounter++
if drainedCount <= 3 || drainedCount%50 == 0 { if jitterDrainLogCounter <= 3 || jitterDrainLogCounter%1000 == 0 {
log.Debug("jitter: draining seq=%d for %s (buf=%d emptyBufs=%d)", log.Debug("jitter: draining seq=%d for %s (buf=%d emptyBufs=%d)",
pkt.Sequence, e.User.Name, len(jitterBuf), len(emptyBufs)) pkt.Sequence, e.User.Name, len(jitterBuf), len(emptyBufs))
} }