直播:后台 JWT 推流、前台画中画;WebRTC 服务与 Nginx WebSocket 代理
Made-with: Cursor
This commit is contained in:
250
server/vendor/github.com/pion/sctp/rtx_timer.go
generated
vendored
Normal file
250
server/vendor/github.com/pion/sctp/rtx_timer.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package sctp
|
||||
|
||||
import (
|
||||
"math"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
// RTO.Initial in msec
|
||||
rtoInitial float64 = 1.0 * 1000
|
||||
|
||||
// RTO.Min in msec
|
||||
rtoMin float64 = 1.0 * 1000
|
||||
|
||||
// RTO.Max in msec
|
||||
defaultRTOMax float64 = 60.0 * 1000
|
||||
|
||||
// RTO.Alpha
|
||||
rtoAlpha float64 = 0.125
|
||||
|
||||
// RTO.Beta
|
||||
rtoBeta float64 = 0.25
|
||||
|
||||
// Max.Init.Retransmits:
|
||||
maxInitRetrans uint = 8
|
||||
|
||||
// Path.Max.Retrans
|
||||
pathMaxRetrans uint = 5
|
||||
|
||||
noMaxRetrans uint = 0
|
||||
)
|
||||
|
||||
// rtoManager manages Rtx timeout values.
|
||||
// This is an implementation of RFC 4960 sec 6.3.1.
|
||||
type rtoManager struct {
|
||||
srtt float64
|
||||
rttvar float64
|
||||
rto float64
|
||||
noUpdate bool
|
||||
mutex sync.RWMutex
|
||||
rtoMax float64
|
||||
}
|
||||
|
||||
// newRTOManager creates a new rtoManager.
|
||||
func newRTOManager(rtoMax float64) *rtoManager {
|
||||
mgr := rtoManager{
|
||||
rto: rtoInitial,
|
||||
rtoMax: rtoMax,
|
||||
}
|
||||
if mgr.rtoMax == 0 {
|
||||
mgr.rtoMax = defaultRTOMax
|
||||
}
|
||||
return &mgr
|
||||
}
|
||||
|
||||
// setNewRTT takes a newly measured RTT then adjust the RTO in msec.
|
||||
func (m *rtoManager) setNewRTT(rtt float64) float64 {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.noUpdate {
|
||||
return m.srtt
|
||||
}
|
||||
|
||||
if m.srtt == 0 {
|
||||
// First measurement
|
||||
m.srtt = rtt
|
||||
m.rttvar = rtt / 2
|
||||
} else {
|
||||
// Subsequent rtt measurement
|
||||
m.rttvar = (1-rtoBeta)*m.rttvar + rtoBeta*(math.Abs(m.srtt-rtt))
|
||||
m.srtt = (1-rtoAlpha)*m.srtt + rtoAlpha*rtt
|
||||
}
|
||||
m.rto = math.Min(math.Max(m.srtt+4*m.rttvar, rtoMin), m.rtoMax)
|
||||
return m.srtt
|
||||
}
|
||||
|
||||
// getRTO simply returns the current RTO in msec.
|
||||
func (m *rtoManager) getRTO() float64 {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
return m.rto
|
||||
}
|
||||
|
||||
// reset resets the RTO variables to the initial values.
|
||||
func (m *rtoManager) reset() {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
if m.noUpdate {
|
||||
return
|
||||
}
|
||||
|
||||
m.srtt = 0
|
||||
m.rttvar = 0
|
||||
m.rto = rtoInitial
|
||||
}
|
||||
|
||||
// set RTO value for testing
|
||||
func (m *rtoManager) setRTO(rto float64, noUpdate bool) {
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
m.rto = rto
|
||||
m.noUpdate = noUpdate
|
||||
}
|
||||
|
||||
// rtxTimerObserver is the inteface to a timer observer.
|
||||
// NOTE: Observers MUST NOT call start() or stop() method on rtxTimer
|
||||
// from within these callbacks.
|
||||
type rtxTimerObserver interface {
|
||||
onRetransmissionTimeout(timerID int, n uint)
|
||||
onRetransmissionFailure(timerID int)
|
||||
}
|
||||
|
||||
type rtxTimerState uint8
|
||||
|
||||
const (
|
||||
rtxTimerStopped rtxTimerState = iota
|
||||
rtxTimerStarted
|
||||
rtxTimerClosed
|
||||
)
|
||||
|
||||
// rtxTimer provides the retnransmission timer conforms with RFC 4960 Sec 6.3.1
|
||||
type rtxTimer struct {
|
||||
timer *time.Timer
|
||||
observer rtxTimerObserver
|
||||
id int
|
||||
maxRetrans uint
|
||||
rtoMax float64
|
||||
mutex sync.Mutex
|
||||
rto float64
|
||||
nRtos uint
|
||||
state rtxTimerState
|
||||
pending uint8
|
||||
}
|
||||
|
||||
// newRTXTimer creates a new retransmission timer.
|
||||
// if maxRetrans is set to 0, it will keep retransmitting until stop() is called.
|
||||
// (it will never make onRetransmissionFailure() callback.
|
||||
func newRTXTimer(id int, observer rtxTimerObserver, maxRetrans uint,
|
||||
rtoMax float64,
|
||||
) *rtxTimer {
|
||||
timer := rtxTimer{
|
||||
id: id,
|
||||
observer: observer,
|
||||
maxRetrans: maxRetrans,
|
||||
rtoMax: rtoMax,
|
||||
}
|
||||
if timer.rtoMax == 0 {
|
||||
timer.rtoMax = defaultRTOMax
|
||||
}
|
||||
timer.timer = time.AfterFunc(math.MaxInt64, timer.timeout)
|
||||
timer.timer.Stop()
|
||||
return &timer
|
||||
}
|
||||
|
||||
func (t *rtxTimer) calculateNextTimeout() time.Duration {
|
||||
timeout := calculateNextTimeout(t.rto, t.nRtos, t.rtoMax)
|
||||
return time.Duration(timeout) * time.Millisecond
|
||||
}
|
||||
|
||||
func (t *rtxTimer) timeout() {
|
||||
t.mutex.Lock()
|
||||
if t.pending--; t.pending == 0 && t.state == rtxTimerStarted {
|
||||
if t.nRtos++; t.maxRetrans == 0 || t.nRtos <= t.maxRetrans {
|
||||
t.timer.Reset(t.calculateNextTimeout())
|
||||
t.pending++
|
||||
defer t.observer.onRetransmissionTimeout(t.id, t.nRtos)
|
||||
} else {
|
||||
t.state = rtxTimerStopped
|
||||
defer t.observer.onRetransmissionFailure(t.id)
|
||||
}
|
||||
}
|
||||
t.mutex.Unlock()
|
||||
}
|
||||
|
||||
// start starts the timer.
|
||||
func (t *rtxTimer) start(rto float64) bool {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
// this timer is already closed or aleady running
|
||||
if t.state != rtxTimerStopped {
|
||||
return false
|
||||
}
|
||||
|
||||
// Note: rto value is intentionally not capped by RTO.Min to allow
|
||||
// fast timeout for the tests. Non-test code should pass in the
|
||||
// rto generated by rtoManager getRTO() method which caps the
|
||||
// value at RTO.Min or at RTO.Max.
|
||||
t.rto = rto
|
||||
t.nRtos = 0
|
||||
t.state = rtxTimerStarted
|
||||
t.pending++
|
||||
t.timer.Reset(t.calculateNextTimeout())
|
||||
return true
|
||||
}
|
||||
|
||||
// stop stops the timer.
|
||||
func (t *rtxTimer) stop() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.state == rtxTimerStarted {
|
||||
if t.timer.Stop() {
|
||||
t.pending--
|
||||
}
|
||||
t.state = rtxTimerStopped
|
||||
}
|
||||
}
|
||||
|
||||
// closes the timer. this is similar to stop() but subsequent start() call
|
||||
// will fail (the timer is no longer usable)
|
||||
func (t *rtxTimer) close() {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
if t.state == rtxTimerStarted && t.timer.Stop() {
|
||||
t.pending--
|
||||
}
|
||||
t.state = rtxTimerClosed
|
||||
}
|
||||
|
||||
// isRunning tests if the timer is running.
|
||||
// Debug purpose only
|
||||
func (t *rtxTimer) isRunning() bool {
|
||||
t.mutex.Lock()
|
||||
defer t.mutex.Unlock()
|
||||
|
||||
return t.state == rtxTimerStarted
|
||||
}
|
||||
|
||||
func calculateNextTimeout(rto float64, nRtos uint, rtoMax float64) float64 {
|
||||
// RFC 4096 sec 6.3.3. Handle T3-rtx Expiration
|
||||
// E2) For the destination address for which the timer expires, set RTO
|
||||
// <- RTO * 2 ("back off the timer"). The maximum value discussed
|
||||
// in rule C7 above (RTO.max) may be used to provide an upper bound
|
||||
// to this doubling operation.
|
||||
if nRtos < 31 {
|
||||
m := 1 << nRtos
|
||||
return math.Min(rto*float64(m), rtoMax)
|
||||
}
|
||||
return rtoMax
|
||||
}
|
||||
Reference in New Issue
Block a user