bound the configured audio buffer count
Buffers had a lower bound but no upper one, and it is allocated per speaking user twice over: as a queue of decoded frames and as OpenAL playback buffers. Each buffer holds up to one maximum sized frame, so a large value multiplied by a populated channel is a substantial amount of memory. Cap it, and reject the flag up front so the failure names the flag rather than surfacing later as a dial error. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0d62f745ca
commit
ef9bd19fc9
@@ -38,6 +38,12 @@ type Config struct {
|
|||||||
Buffers int
|
Buffers int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MaximumBuffers caps Config.Buffers. Each buffer holds up to one maximum
|
||||||
|
// sized audio frame and is allocated per speaking user, so a large value
|
||||||
|
// multiplied by a populated channel is a substantial amount of memory. A few
|
||||||
|
// seconds of buffering is already far more than playback needs.
|
||||||
|
const MaximumBuffers = 1024
|
||||||
|
|
||||||
// NewConfig returns a new Config struct with default values set.
|
// NewConfig returns a new Config struct with default values set.
|
||||||
func NewConfig() *Config {
|
func NewConfig() *Config {
|
||||||
return &Config{
|
return &Config{
|
||||||
@@ -64,6 +70,12 @@ func (c *Config) Validate() error {
|
|||||||
if c.Buffers <= 0 {
|
if c.Buffers <= 0 {
|
||||||
return fmt.Errorf("gumble: Buffers must be positive")
|
return fmt.Errorf("gumble: Buffers must be positive")
|
||||||
}
|
}
|
||||||
|
// Buffers is allocated per speaking user, both as a queue of decoded
|
||||||
|
// frames and as OpenAL playback buffers, so an unbounded value multiplies
|
||||||
|
// straight into memory use as a channel fills up.
|
||||||
|
if c.Buffers > MaximumBuffers {
|
||||||
|
return fmt.Errorf("gumble: Buffers must be at most %d", MaximumBuffers)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package gumble
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
// Regression: Buffers had no upper bound, but it is allocated per speaking
|
||||||
|
// user both as a decoded-frame queue and as OpenAL playback buffers.
|
||||||
|
func TestConfigRejectsOversizedBuffers(t *testing.T) {
|
||||||
|
config := NewConfig()
|
||||||
|
config.Buffers = MaximumBuffers + 1
|
||||||
|
if err := config.Validate(); err == nil {
|
||||||
|
t.Fatal("expected Buffers above the maximum to be rejected")
|
||||||
|
}
|
||||||
|
config.Buffers = MaximumBuffers
|
||||||
|
if err := config.Validate(); err != nil {
|
||||||
|
t.Fatalf("Buffers at the maximum should be accepted: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -105,6 +105,10 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
handle_raw_error(err)
|
handle_raw_error(err)
|
||||||
}
|
}
|
||||||
|
if *buffers <= 0 || *buffers > gumble.MaximumBuffers {
|
||||||
|
handle_raw_error(fmt.Errorf("buffers must be between 1 and %d, got %d",
|
||||||
|
gumble.MaximumBuffers, *buffers))
|
||||||
|
}
|
||||||
|
|
||||||
// Set up logging
|
// Set up logging
|
||||||
var level barnlog.Level
|
var level barnlog.Level
|
||||||
|
|||||||
Reference in New Issue
Block a user