Keep OpenAL jitter playback continuous
This commit is contained in:
committed by
Brandon McGinty
parent
5b0879ddaa
commit
99f1f4b9ab
@@ -52,8 +52,16 @@ const recorderOutgoingSource uint32 = ^uint32(0)
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
maxBufferSize = 11520 // Max frame size (2880) * bytes per stereo sample (4)
|
maxBufferSize = 11520 // Max frame size (2880) * bytes per stereo sample (4)
|
||||||
|
jitterMinPackets = 3
|
||||||
|
jitterMaxPackets = 10
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// jitterPlaybackReady holds the initial playout delay only once. Requiring
|
||||||
|
// the minimum on every packet drains and refills the renderer in bursts.
|
||||||
|
func jitterPlaybackReady(started bool, buffered int) bool {
|
||||||
|
return started || buffered >= jitterMinPackets
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
ErrState = errors.New("gumbleopenal: invalid state")
|
ErrState = errors.New("gumbleopenal: invalid state")
|
||||||
ErrMic = errors.New("gumbleopenal: microphone disconnected or misconfigured")
|
ErrMic = errors.New("gumbleopenal: microphone disconnected or misconfigured")
|
||||||
@@ -451,15 +459,10 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Jitter buffer: collects incoming packets, reorders by
|
// Jitter buffer: collects incoming packets, reorders by
|
||||||
// sequence number, and releases them in order after a small
|
// sequence number, and releases them after a small initial delay.
|
||||||
// initial delay (3-5 packets / 30-50ms).
|
|
||||||
const (
|
|
||||||
jitterMinPackets = 3 // minimum packets before playout starts
|
|
||||||
jitterMaxPackets = 10 // maximum buffered packets before dropping oldest
|
|
||||||
)
|
|
||||||
var jitterBuf []*gumble.AudioPacket
|
var jitterBuf []*gumble.AudioPacket
|
||||||
var jitterNextSeq int64
|
var jitterNextSeq int64
|
||||||
var jitterInit bool
|
var jitterInit, jitterStarted bool
|
||||||
|
|
||||||
// insertSorted inserts a packet into the jitter buffer sorted
|
// insertSorted inserts a packet into the jitter buffer sorted
|
||||||
// by sequence number.
|
// by sequence number.
|
||||||
@@ -509,10 +512,13 @@ func (s *Stream) OnAudioStream(e *gumble.AudioStreamEvent) {
|
|||||||
jitterInit = true
|
jitterInit = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only start playing when we have enough buffered packets
|
// Hold only the initial packets. Once playback starts, drain every
|
||||||
if len(jitterBuf) < jitterMinPackets {
|
// ready packet so the renderer is fed continuously rather than in
|
||||||
|
// bursts of jitterMinPackets packets.
|
||||||
|
if !jitterPlaybackReady(jitterStarted, len(jitterBuf)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
jitterStarted = true
|
||||||
|
|
||||||
// Drain all packets that are ready (in sequence order)
|
// Drain all packets that are ready (in sequence order)
|
||||||
for {
|
for {
|
||||||
|
|||||||
@@ -48,6 +48,18 @@ func TestStopSourceWaitsForWorker(t *testing.T) {
|
|||||||
<-returned
|
<-returned
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJitterPlaybackDelayAppliesOnlyAtStartup(t *testing.T) {
|
||||||
|
if jitterPlaybackReady(false, jitterMinPackets-1) {
|
||||||
|
t.Fatal("jitter playback started before initial buffer filled")
|
||||||
|
}
|
||||||
|
if !jitterPlaybackReady(false, jitterMinPackets) {
|
||||||
|
t.Fatal("jitter playback did not start after initial buffer filled")
|
||||||
|
}
|
||||||
|
if !jitterPlaybackReady(true, 1) {
|
||||||
|
t.Fatal("jitter playback paused while refilling after startup")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRenderRejectsWorkAfterShutdown(t *testing.T) {
|
func TestRenderRejectsWorkAfterShutdown(t *testing.T) {
|
||||||
s := &Stream{renderClosed: true}
|
s := &Stream{renderClosed: true}
|
||||||
called := false
|
called := false
|
||||||
|
|||||||
Reference in New Issue
Block a user