diff --git a/gumble/gumble/client.go b/gumble/gumble/client.go index a80507f..7b05c1a 100644 --- a/gumble/gumble/client.go +++ b/gumble/gumble/client.go @@ -263,11 +263,15 @@ func (c *Client) AudioOutgoing() chan<- AudioBuffer { ch := make(chan AudioBuffer) go func() { var seq int64 + frameStep := int64(c.Config.AudioFrameSize() / AudioDefaultFrameSize) + if frameStep < 1 { + frameStep = 1 + } previous := <-ch for p := range ch { previous.writeAudio(c, seq, false) previous = p - seq = (seq + 1) % math.MaxInt32 + seq = (seq + frameStep) % math.MaxInt32 } if previous != nil { previous.writeAudio(c, seq, true) diff --git a/main.go b/main.go index 734bba5..57381e2 100644 --- a/main.go +++ b/main.go @@ -115,6 +115,7 @@ func main() { serverSet := false usernameSet := false buffers := flag.Int("buffers", 16, "number of audio buffers to use") + audioInterval := flag.Int("audio-interval", 10, "outgoing audio packet duration in ms (10, 20, 40, or 60)") jitterBuffer := flag.Int("jitter-buffer", 40, "incoming per-user audio buffer in ms (0, 20, 40, or 60)") profile := flag.Bool("profile", false, "add http server to serve profiles") noiseSuppressionEnabled := flag.Bool("noise-suppression", false, "enable noise suppression for microphone input") @@ -123,6 +124,10 @@ func main() { logFile := flag.String("logfile", "", "write logs to this file (logging is disabled when omitted)") flag.Parse() + selectedAudioInterval, err := audioIntervalDuration(*audioInterval) + if err != nil { + handle_raw_error(err) + } selectedJitterBuffer, err := jitterBufferDuration(*jitterBuffer) if err != nil { handle_raw_error(err) @@ -219,6 +224,7 @@ func main() { NoiseSuppressor: noise.NewSuppressor(), } b.Config.Buffers = *buffers + b.Config.AudioInterval = selectedAudioInterval b.Config.DisableUDP = *tcpOnly b.Config.IncomingAudioBuffer = selectedJitterBuffer @@ -260,6 +266,18 @@ func main() { handle_error(&b) } +// audioIntervalDuration converts the packet duration requested at startup to +// one of the Opus durations supported by Mumble. +func audioIntervalDuration(milliseconds int) (time.Duration, error) { + interval := time.Duration(milliseconds) * time.Millisecond + switch interval { + case 10 * time.Millisecond, 20 * time.Millisecond, 40 * time.Millisecond, 60 * time.Millisecond: + return interval, nil + default: + return 0, fmt.Errorf("audio interval must be 10, 20, 40, or 60 ms, got %d", milliseconds) + } +} + // jitterBufferDuration converts the requested incoming playout delay to a // supported duration. Zero starts playback without an initial safety buffer. func jitterBufferDuration(milliseconds int) (time.Duration, error) {