diff --git a/gumble/gumble/audio.go b/gumble/gumble/audio.go index ceb10b2..5bde563 100644 --- a/gumble/gumble/audio.go +++ b/gumble/gumble/audio.go @@ -53,12 +53,10 @@ type AudioStreamEvent struct { type AudioBuffer []int16 func (a AudioBuffer) writeAudio(client *Client, seq int64, final bool) error { - // Choose encoder based on whether buffer size indicates stereo or mono + // Always use the mono encoder for voice transmission. The stereo + // encoder is only used when explicitly enabled for file playback. encoder := client.AudioEncoder - frameSize := client.Config.AudioFrameSize() - if len(a) == frameSize*AudioChannels && client.AudioEncoderStereo != nil { - encoder = client.AudioEncoderStereo - } else if client.IsStereoEncoderEnabled() && client.AudioEncoderStereo != nil { + if client.IsStereoEncoderEnabled() && client.AudioEncoderStereo != nil { encoder = client.AudioEncoderStereo } if encoder == nil { diff --git a/gumble/gumbleopenal/stream.go b/gumble/gumbleopenal/stream.go index 819f35e..3fe561b 100644 --- a/gumble/gumbleopenal/stream.go +++ b/gumble/gumbleopenal/stream.go @@ -503,10 +503,21 @@ func (s *Stream) sourceRoutine(inputDevice *string) { recorder.RecordAudioFrame(recorderOutgoingSource, outputBuffer) } } else if hasMicInput { - // Send mic when no file is playing - outgoing <- gumble.AudioBuffer(int16Buffer) + // Send mic when no file is playing. If the microphone is + // stereo, downmix to mono since Mumble voice transmission + // uses mono Opus encoding. + outBuf := int16Buffer + if s.sourceChannels == 2 { + monoBuf := make([]int16, frameSize) + for i := 0; i < frameSize; i++ { + // Average left and right channels + monoBuf[i] = int16((int32(int16Buffer[i*2]) + int32(int16Buffer[i*2+1])) / 2) + } + outBuf = monoBuf + } + outgoing <- gumble.AudioBuffer(outBuf) if recorder := s.getRecorder(); recorder != nil { - recorder.RecordAudioFrame(recorderOutgoingSource, int16Buffer) + recorder.RecordAudioFrame(recorderOutgoingSource, outBuf) } } }