fix: move reclaim() outside processAudioPacket to fix buffer corruption

processAudioPacket accepted reclaim as a closure that captured the
outer goroutine's emptyBufs variable. When reclaim() appended buffers
inside the function, it mutated the outer variable, but the function
also returned its own copy. The caller then overwrote the outer
variable with the returned copy, losing the buffers reclaimed by
reclaim(). This caused OpenAL buffer starvation and audio dropouts.

Move reclaim() calls to the main loop before processAudioPacket, and
remove the reclaim parameter from the function. The caller now always
owns the emptyBufs lifecycle.
This commit is contained in:
Brandon McGinty (deepseek)
2026-08-08 21:19:26 -04:00
committed by Brandon McGinty
parent 0858cd3542
commit 3e98e93cfb
+7 -4
View File
@@ -338,7 +338,8 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
if pkt == nil {
break
}
emptyBufs = s.processAudioPacket(pkt, e.User, &source, emptyBufs, &raw, reclaim)
reclaim()
emptyBufs = s.processAudioPacket(pkt, e.User, &source, emptyBufs, &raw)
}
}
@@ -351,7 +352,8 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
pkt = popNext()
}
if pkt != nil {
emptyBufs = s.processAudioPacket(pkt, e.User, &source, emptyBufs, &raw, reclaim)
reclaim()
emptyBufs = s.processAudioPacket(pkt, e.User, &source, emptyBufs, &raw)
}
}
reclaim()
@@ -362,7 +364,9 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
// processAudioPacket decodes and queues a single audio packet for playback.
// Returns the updated emptyBufs slice after consuming a buffer.
func (s *Stream) processAudioPacket(packet *gumble.AudioPacket, user *gumble.User, source *openal.Source, emptyBufs openal.Buffers, raw *[maxBufferSize]byte, reclaim func()) openal.Buffers {
// The caller must call reclaim() before invoking this to ensure buffers
// are available.
func (s *Stream) processAudioPacket(packet *gumble.AudioPacket, user *gumble.User, source *openal.Source, emptyBufs openal.Buffers, raw *[maxBufferSize]byte) openal.Buffers {
samples := len(packet.AudioBuffer)
if samples > cap(*raw)/2 {
return emptyBufs
@@ -455,7 +459,6 @@ func (s *Stream) processAudioPacket(packet *gumble.AudioPacket, user *gumble.Use
recorder.RecordAudioFrame(user.Session, recordBuffer[:recordPtr])
}
reclaim()
if len(emptyBufs) == 0 {
return emptyBufs
}