diff --git a/client.go b/client.go index ca6ebff..2e66860 100644 --- a/client.go +++ b/client.go @@ -99,7 +99,7 @@ func (b *Barnard) connect(reconnect bool) bool { }) // Initialize stereo encoder for file playback - b.Client.AudioEncoderStereo = opus.NewStereoEncoder() + b.Client.SetStereoEncoder(opus.NewStereoEncoder()) // Initialize file player b.FileStreamMutex.Lock() diff --git a/gumble/gumble/audio.go b/gumble/gumble/audio.go index fbf74a1..358225d 100644 --- a/gumble/gumble/audio.go +++ b/gumble/gumble/audio.go @@ -53,28 +53,30 @@ type AudioStreamEvent struct { type AudioBuffer []int16 func (a AudioBuffer) writeAudio(client *Client, seq int64, final bool) error { - // Always use the mono encoder for voice transmission. The stereo - // encoder is only used when explicitly enabled for file playback. + // Encoding shares mutable codec state with server-configuration and file + // playback changes. Keep the client read lock through Encode and Reset so a + // stereo encoder cannot be replaced or reset while it is in use. + client.volatile.RLock() encoder := client.AudioEncoder - if client.IsStereoEncoderEnabled() && client.AudioEncoderStereo != nil { + if client.useStereoEncoder && client.AudioEncoderStereo != nil { encoder = client.AudioEncoderStereo } if encoder == nil { + client.volatile.RUnlock() return nil } - dataBytes := client.Config.AudioDataBytes - raw, err := encoder.Encode(a, len(a), dataBytes) + raw, err := encoder.Encode(a, len(a), client.Config.AudioDataBytes) if final { - defer encoder.Reset() + encoder.Reset() } - if err != nil { - return err - } - var targetID byte if target := client.VoiceTarget; target != nil { targetID = byte(target.ID) } + client.volatile.RUnlock() + if err != nil { + return err + } return client.WriteAudio(byte(4), targetID, seq, final, raw, nil, nil, nil) } diff --git a/gumble/gumble/client.go b/gumble/gumble/client.go index 4ef3f5c..464c2ca 100644 --- a/gumble/gumble/client.go +++ b/gumble/gumble/client.go @@ -343,6 +343,13 @@ func (c *Client) Send(message Message) { message.writeMessage(c) } +// SetStereoEncoder installs the encoder used for stereo file playback. +func (c *Client) SetStereoEncoder(encoder AudioEncoder) { + c.volatile.Lock() + defer c.volatile.Unlock() + c.AudioEncoderStereo = encoder +} + // EnableStereoEncoder switches to stereo encoding for file playback. func (c *Client) EnableStereoEncoder() { c.volatile.Lock()