Attempt to fix a bug that can randomly drop audio streams.
This commit is contained in:
@@ -86,6 +86,8 @@ type AudioPacket struct {
|
|||||||
Sender *User
|
Sender *User
|
||||||
Target *VoiceTarget
|
Target *VoiceTarget
|
||||||
Final bool
|
Final bool
|
||||||
|
// Channels is the number of interleaved PCM channels in AudioBuffer.
|
||||||
|
Channels int
|
||||||
// LocallyMuted and LocalMuteGeneration snapshot the receiver's local mute
|
// LocallyMuted and LocalMuteGeneration snapshot the receiver's local mute
|
||||||
// state when the packet entered the playback queue.
|
// state when the packet entered the playback queue.
|
||||||
LocallyMuted bool
|
LocallyMuted bool
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ type AudioEncoder interface {
|
|||||||
// AudioDecoder decodes an encoded byte slice to a chunk of PCM audio samples.
|
// AudioDecoder decodes an encoded byte slice to a chunk of PCM audio samples.
|
||||||
type AudioDecoder interface {
|
type AudioDecoder interface {
|
||||||
ID() int
|
ID() int
|
||||||
|
Channels() int
|
||||||
Decode(data []byte, frameSize int) ([]int16, error)
|
Decode(data []byte, frameSize int) ([]int16, error)
|
||||||
Reset()
|
Reset()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,6 +152,7 @@ func (c *Client) handleUDPTunnel(buffer []byte) error {
|
|||||||
Client: c,
|
Client: c,
|
||||||
Sender: user,
|
Sender: user,
|
||||||
Final: final,
|
Final: final,
|
||||||
|
Channels: decoder.Channels(),
|
||||||
LocallyMuted: locallyMuted,
|
LocallyMuted: locallyMuted,
|
||||||
LocalMuteGeneration: localMuteGeneration,
|
LocalMuteGeneration: localMuteGeneration,
|
||||||
Target: &VoiceTarget{
|
Target: &VoiceTarget{
|
||||||
|
|||||||
@@ -41,6 +41,23 @@ func shouldStartPlayback(state openal.State, queued int32, final bool) bool {
|
|||||||
return state != openal.Playing && queued > 0 && (queued >= playbackPrebufferBuffers || final)
|
return state != openal.Playing && queued > 0 && (queued >= playbackPrebufferBuffers || final)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func playbackLayout(packet *gumble.AudioPacket) (openal.Format, int, bool) {
|
||||||
|
if packet == nil || len(packet.AudioBuffer) == 0 {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
switch packet.Channels {
|
||||||
|
case gumble.AudioMonoChannels:
|
||||||
|
return openal.FormatMono16, len(packet.AudioBuffer), true
|
||||||
|
case gumble.AudioChannels:
|
||||||
|
if len(packet.AudioBuffer)%gumble.AudioChannels != 0 {
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
return openal.FormatStereo16, len(packet.AudioBuffer) / gumble.AudioChannels, true
|
||||||
|
default:
|
||||||
|
return 0, 0, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type playbackCommand struct {
|
type playbackCommand struct {
|
||||||
gain float32
|
gain float32
|
||||||
muted bool
|
muted bool
|
||||||
@@ -550,14 +567,14 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var boost uint16 = uint16(1)
|
var boost uint16 = uint16(1)
|
||||||
samples := len(packet.AudioBuffer)
|
if len(packet.AudioBuffer) == 0 {
|
||||||
if samples == 0 {
|
|
||||||
if shouldStartPlayback(source.State(), source.BuffersQueued(), packet.Final) {
|
if shouldStartPlayback(source.State(), source.BuffersQueued(), packet.Final) {
|
||||||
source.Play()
|
source.Play()
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if samples > cap(raw)/2 {
|
format, samples, validLayout := playbackLayout(packet)
|
||||||
|
if !validLayout || len(packet.AudioBuffer) > cap(raw)/2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -569,13 +586,7 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
|||||||
recordBuffer = make([]int16, len(packet.AudioBuffer)*gumble.AudioChannels)
|
recordBuffer = make([]int16, len(packet.AudioBuffer)*gumble.AudioChannels)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if sample count suggests stereo data
|
isStereo := packet.Channels == gumble.AudioChannels
|
||||||
isStereo := samples > gumble.AudioDefaultFrameSize && samples%2 == 0
|
|
||||||
format := openal.FormatMono16
|
|
||||||
if isStereo {
|
|
||||||
format = openal.FormatStereo16
|
|
||||||
samples = samples / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
rawPtr := 0
|
rawPtr := 0
|
||||||
if isStereo {
|
if isStereo {
|
||||||
|
|||||||
@@ -32,6 +32,24 @@ func TestShouldStartPlayback(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPlaybackLayoutUsesExplicitStereoChannelCount(t *testing.T) {
|
||||||
|
packet := &gumble.AudioPacket{
|
||||||
|
Channels: gumble.AudioChannels,
|
||||||
|
AudioBuffer: make(gumble.AudioBuffer, gumble.AudioDefaultFrameSize),
|
||||||
|
}
|
||||||
|
|
||||||
|
format, frames, ok := playbackLayout(packet)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("expected a valid short stereo packet")
|
||||||
|
}
|
||||||
|
if format != openal.FormatStereo16 {
|
||||||
|
t.Fatalf("format = %v, want stereo", format)
|
||||||
|
}
|
||||||
|
if frames != gumble.AudioDefaultFrameSize/gumble.AudioChannels {
|
||||||
|
t.Fatalf("frames = %d, want %d", frames, gumble.AudioDefaultFrameSize/gumble.AudioChannels)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestSendOutgoingAudioStopsWhileSendIsBlocked(t *testing.T) {
|
func TestSendOutgoingAudioStopsWhileSendIsBlocked(t *testing.T) {
|
||||||
stop := make(chan struct{})
|
stop := make(chan struct{})
|
||||||
outgoing := make(chan gumble.AudioBuffer)
|
outgoing := make(chan gumble.AudioBuffer)
|
||||||
|
|||||||
@@ -88,6 +88,10 @@ func (*Decoder) ID() int {
|
|||||||
return ID
|
return ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) Channels() int {
|
||||||
|
return d.channels
|
||||||
|
}
|
||||||
|
|
||||||
func (d *Decoder) Decode(data []byte, frameSize int) ([]int16, error) {
|
func (d *Decoder) Decode(data []byte, frameSize int) ([]int16, error) {
|
||||||
// Allocate buffer for stereo - frameSize is per channel
|
// Allocate buffer for stereo - frameSize is per channel
|
||||||
pcm := make([]int16, frameSize*gumble.AudioChannels)
|
pcm := make([]int16, frameSize*gumble.AudioChannels)
|
||||||
|
|||||||
Reference in New Issue
Block a user