From 5c1cd69d65a50ab2910e4e945184feec9a94e040 Mon Sep 17 00:00:00 2001 From: "Brandon McGinty (deepseek)" Date: Sat, 8 Aug 2026 19:17:31 -0400 Subject: [PATCH] fix: configure Opus encoder bitrate from available bandwidth Replace SetBitrateToMax() with dynamic bitrate configuration based on the per-frame byte budget (AudioDataBytes). Previously, the encoder always targeted maximum bitrate (~510 kbps) and relied on output truncation when frames exceeded the available bandwidth. This could produce truncated/invalid Opus frames when the server's max bandwidth is lower than the encoder's target. The bitrate is now recalculated on every Encode() call as: maxDataBytes * 8 * 100 (bits per second for 10ms frames) This ensures the encoder produces frames that fit within the byte budget without truncation. --- gumble/opus/opus.go | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/gumble/opus/opus.go b/gumble/opus/opus.go index f0976e4..23e8eee 100644 --- a/gumble/opus/opus.go +++ b/gumble/opus/opus.go @@ -29,9 +29,8 @@ func (*generator) ID() int { func (*generator) NewEncoder() gumble.AudioEncoder { // Force mono for voice transmission e, _ := opus.NewEncoder(gumble.AudioSampleRate, VoiceChannels, opus.AppVoIP) - _ = e.SetBitrateToMax() return &Encoder{ - e, + Encoder: e, } } @@ -39,9 +38,8 @@ func (*generator) NewEncoder() gumble.AudioEncoder { func NewStereoEncoder() gumble.AudioEncoder { // Create stereo encoder for file playback e, _ := opus.NewEncoder(gumble.AudioSampleRate, gumble.AudioChannels, opus.AppAudio) - _ = e.SetBitrateToMax() return &Encoder{ - e, + Encoder: e, } } @@ -65,6 +63,13 @@ func (*Encoder) ID() int { } func (e *Encoder) Encode(pcm []int16, _, maxDataBytes int) ([]byte, error) { + // Set the encoder bitrate to match the available bandwidth per frame. + // The bitrate is: maxDataBytes * 8 (bits per byte) * 100 (10ms frames per second). + // Opus encodes best when the bitrate target is set properly rather than + // relying on truncation, which can produce incomplete or corrupt frames. + bitrate := maxDataBytes * 8 * 100 + _ = e.Encoder.SetBitrate(bitrate) + buf := make([]byte, maxDataBytes) n, err := e.Encoder.Encode(pcm, buf) if err != nil {