首次推送
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
package teamspeak
|
||||
|
||||
import "time"
|
||||
|
||||
type receiveTimeline struct {
|
||||
clientID int
|
||||
decoder voiceDecoder
|
||||
packets map[uint16]voicePacket
|
||||
expected uint16
|
||||
initialized bool
|
||||
ready bool
|
||||
plc int
|
||||
lossWait int
|
||||
muted bool
|
||||
speaking bool
|
||||
starved bool
|
||||
hasPlayed bool
|
||||
lastPacket time.Time
|
||||
lastActive time.Time
|
||||
pending []int16
|
||||
lastReal bool
|
||||
}
|
||||
|
||||
const (
|
||||
receiveLossWaitTicks = 2
|
||||
receiveTalkSpurtGap = 400 * time.Millisecond
|
||||
receiveMaxPending = receiveFrameInterleavedSamples * 12
|
||||
)
|
||||
|
||||
func newReceiveTimeline(clientID int, decoder voiceDecoder) *receiveTimeline {
|
||||
return &receiveTimeline{clientID: clientID, decoder: decoder, packets: make(map[uint16]voicePacket)}
|
||||
}
|
||||
|
||||
func (t *receiveTimeline) release() {
|
||||
if t.decoder != nil {
|
||||
t.decoder.Release()
|
||||
t.decoder = nil
|
||||
}
|
||||
}
|
||||
|
||||
func seqAhead(a, b uint16) bool { return int16(a-b) > 0 }
|
||||
|
||||
func (t *receiveTimeline) resetForTalkSpurt(sequence uint16) {
|
||||
clear(t.packets)
|
||||
t.pending = t.pending[:0]
|
||||
t.expected = sequence
|
||||
t.initialized = true
|
||||
t.ready = false
|
||||
t.plc = 0
|
||||
t.lossWait = 0
|
||||
t.starved = false
|
||||
}
|
||||
|
||||
func (t *receiveTimeline) push(p voicePacket) {
|
||||
if _, exists := t.packets[p.sequence]; exists {
|
||||
return
|
||||
}
|
||||
|
||||
// A quiet gap or an exhausted timeline starts a new packet epoch. This is
|
||||
// deliberately checked before the normal forward-window rejection so a
|
||||
// resumed talk spurt cannot be trapped behind an obsolete expected cursor.
|
||||
if t.initialized && !t.lastPacket.IsZero() &&
|
||||
(p.at.Sub(t.lastPacket) >= receiveTalkSpurtGap ||
|
||||
(t.hasPlayed && t.starved && seqAhead(p.sequence, t.expected) &&
|
||||
int(uint16(p.sequence-t.expected)) > receiveMaxPackets)) {
|
||||
t.resetForTalkSpurt(p.sequence)
|
||||
}
|
||||
if !t.initialized {
|
||||
t.expected = p.sequence
|
||||
t.initialized = true
|
||||
}
|
||||
if p.sequence != t.expected && !seqAhead(p.sequence, t.expected) {
|
||||
return
|
||||
}
|
||||
if seqAhead(p.sequence, t.expected) && int(uint16(p.sequence-t.expected)) > receiveMaxPackets {
|
||||
return
|
||||
}
|
||||
if len(t.packets) >= receiveMaxPackets {
|
||||
return
|
||||
}
|
||||
t.packets[p.sequence] = p
|
||||
t.lastPacket = p.at
|
||||
if len(t.packets) >= receivePrebuffer {
|
||||
t.ready = true
|
||||
}
|
||||
}
|
||||
|
||||
func (t *receiveTimeline) takeFrame(pcm []int16) ([]int16, bool) {
|
||||
if len(pcm) == 0 {
|
||||
return nil, false
|
||||
}
|
||||
if len(t.pending)+len(pcm) > receiveMaxPending {
|
||||
// Keep the newest decoded audio when a decoder returns a long burst.
|
||||
over := len(t.pending) + len(pcm) - receiveMaxPending
|
||||
if over >= len(t.pending) {
|
||||
t.pending = t.pending[:0]
|
||||
} else {
|
||||
t.pending = t.pending[over:]
|
||||
}
|
||||
}
|
||||
t.pending = append(t.pending, pcm...)
|
||||
if len(t.pending) < receiveFrameInterleavedSamples {
|
||||
return nil, false
|
||||
}
|
||||
frame := append([]int16(nil), t.pending[:receiveFrameInterleavedSamples]...)
|
||||
t.pending = t.pending[receiveFrameInterleavedSamples:]
|
||||
return frame, true
|
||||
}
|
||||
|
||||
func (t *receiveTimeline) popPending() ([]int16, bool) {
|
||||
if len(t.pending) < receiveFrameInterleavedSamples {
|
||||
return nil, false
|
||||
}
|
||||
frame := append([]int16(nil), t.pending[:receiveFrameInterleavedSamples]...)
|
||||
t.pending = t.pending[receiveFrameInterleavedSamples:]
|
||||
return frame, true
|
||||
}
|
||||
|
||||
func (t *receiveTimeline) earliestPacket() (uint16, bool) {
|
||||
var earliest uint16
|
||||
found := false
|
||||
for sequence := range t.packets {
|
||||
if !found || seqAhead(earliest, sequence) {
|
||||
earliest, found = sequence, true
|
||||
}
|
||||
}
|
||||
return earliest, found
|
||||
}
|
||||
|
||||
// next returns at most one fixed output frame. It never advances expected while
|
||||
// the packet buffer is empty: an empty buffer is normal talk-spurt silence, not
|
||||
// confirmed packet loss. lastReal distinguishes decoded audio from PLC for UI.
|
||||
func (t *receiveTimeline) next() ([]int16, bool) {
|
||||
t.lastReal = false
|
||||
if frame, ok := t.popPending(); ok {
|
||||
t.starved = false
|
||||
t.lastReal = true
|
||||
return frame, true
|
||||
}
|
||||
if !t.ready || t.decoder == nil {
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
if p, ok := t.packets[t.expected]; ok {
|
||||
delete(t.packets, t.expected)
|
||||
t.expected++
|
||||
t.plc = 0
|
||||
t.lossWait = 0
|
||||
pcm, err := t.decoder.Decode(p.data)
|
||||
if err != nil {
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
frame, active := t.takeFrame(pcm)
|
||||
if active {
|
||||
t.starved = false
|
||||
t.hasPlayed = true
|
||||
t.lastReal = true
|
||||
}
|
||||
return frame, active
|
||||
}
|
||||
|
||||
// Do not PLC ordinary silence. A later packet is evidence of a gap.
|
||||
if _, found := t.earliestPacket(); !found {
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
if t.lossWait < receiveLossWaitTicks {
|
||||
t.lossWait++
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
if t.plc < receiveMaxPLC {
|
||||
t.plc++
|
||||
t.lossWait = 0
|
||||
t.expected++
|
||||
pcm, err := t.decoder.DecodeLost()
|
||||
if err != nil {
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
frame, active := t.takeFrame(pcm)
|
||||
if active {
|
||||
// PLC preserves an existing speaking state but never starts one.
|
||||
t.starved = false
|
||||
}
|
||||
return frame, active
|
||||
}
|
||||
|
||||
if earliest, found := t.earliestPacket(); found {
|
||||
t.expected = earliest
|
||||
t.plc = 0
|
||||
t.lossWait = 0
|
||||
t.starved = false
|
||||
return t.next()
|
||||
}
|
||||
t.starved = true
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func mixPCM16(acc []int32) []byte {
|
||||
out := make([]byte, receiveFrameBytes)
|
||||
for i, sample := range acc {
|
||||
if sample > 32767 {
|
||||
sample = 32767
|
||||
} else if sample < -32768 {
|
||||
sample = -32768
|
||||
}
|
||||
out[2*i], out[2*i+1] = byte(int16(sample)), byte(int16(sample)>>8)
|
||||
}
|
||||
return out
|
||||
}
|
||||
Reference in New Issue
Block a user