mirror of
https://github.com/netbirdio/ice.git
synced 2026-05-22 17:10:58 -07:00
use binding requests to calculate latency for each candidate pair
This commit is contained in:
@@ -15,8 +15,6 @@ import (
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
atomicx "github.com/pion/ice/v3/internal/atomic"
|
||||
stunx "github.com/pion/ice/v3/internal/stun"
|
||||
"github.com/pion/logging"
|
||||
"github.com/pion/mdns"
|
||||
"github.com/pion/stun/v2"
|
||||
@@ -25,6 +23,9 @@ import (
|
||||
"github.com/pion/transport/v3/stdnet"
|
||||
"github.com/pion/transport/v3/vnet"
|
||||
"golang.org/x/net/proxy"
|
||||
|
||||
atomicx "github.com/pion/ice/v3/internal/atomic"
|
||||
stunx "github.com/pion/ice/v3/internal/stun"
|
||||
)
|
||||
|
||||
type bindingRequest struct {
|
||||
@@ -43,6 +44,7 @@ type Agent struct {
|
||||
onConnectionStateChangeHdlr atomic.Value // func(ConnectionState)
|
||||
onSelectedCandidatePairChangeHdlr atomic.Value // func(Candidate, Candidate)
|
||||
onCandidateHdlr atomic.Value // func(Candidate)
|
||||
onSuccessfulBindingResponseHdlr atomic.Value // func(Candidate)
|
||||
|
||||
// State owned by the taskLoop
|
||||
onConnected chan struct{}
|
||||
@@ -648,7 +650,8 @@ func (a *Agent) checkKeepalive() {
|
||||
|
||||
if (a.keepaliveInterval != 0) &&
|
||||
((time.Since(selectedPair.Local.LastSent()) > a.keepaliveInterval) ||
|
||||
(time.Since(selectedPair.Remote.LastReceived()) > a.keepaliveInterval)) {
|
||||
(time.Since(selectedPair.Remote.LastReceived()) > a.keepaliveInterval) ||
|
||||
(time.Since(selectedPair.lastBindingRequest) > a.keepaliveInterval)) {
|
||||
// We use binding request instead of indication to support refresh consent schemas
|
||||
// see https://tools.ietf.org/html/rfc7675
|
||||
a.selector.PingCandidate(selectedPair.Local, selectedPair.Remote)
|
||||
@@ -991,6 +994,9 @@ func (a *Agent) sendBindingRequest(m *stun.Message, local, remote Candidate) {
|
||||
isUseCandidate: m.Contains(stun.AttrUseCandidate),
|
||||
})
|
||||
|
||||
p := a.findPair(local, remote)
|
||||
p.markBindingRequest(m.TransactionID)
|
||||
|
||||
a.sendSTUN(m, local, remote)
|
||||
}
|
||||
|
||||
@@ -1174,7 +1180,7 @@ func (a *Agent) GetSelectedCandidatePair() (*CandidatePair, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &CandidatePair{Local: local, Remote: remote}, nil
|
||||
return &CandidatePair{Local: local, Remote: remote, latency: selectedPair.Latency()}, nil
|
||||
}
|
||||
|
||||
func (a *Agent) getSelectedPair() *CandidatePair {
|
||||
|
||||
@@ -23,6 +23,12 @@ func (a *Agent) OnCandidate(f func(Candidate)) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// OnSuccessfulBindingResponse sets a handler that is fired when a successful binding response is received
|
||||
func (a *Agent) OnSuccessfulBindingResponse(f func(*CandidatePair)) error {
|
||||
a.onSuccessfulBindingResponseHdlr.Store(f)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Agent) onSelectedCandidatePairChange(p *CandidatePair) {
|
||||
if h, ok := a.onSelectedCandidatePairChangeHdlr.Load().(func(Candidate, Candidate)); ok {
|
||||
h(p.Local, p.Remote)
|
||||
@@ -41,6 +47,12 @@ func (a *Agent) onConnectionStateChange(s ConnectionState) {
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) onSuccessfulBindingResponse(p *CandidatePair) {
|
||||
if h, ok := a.onSuccessfulBindingResponseHdlr.Load().(func(*CandidatePair)); ok {
|
||||
h(p)
|
||||
}
|
||||
}
|
||||
|
||||
func (a *Agent) candidatePairRoutine() {
|
||||
for p := range a.chanCandidatePair {
|
||||
a.onSelectedCandidatePairChange(p)
|
||||
|
||||
@@ -5,6 +5,7 @@ package ice
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/pion/stun/v2"
|
||||
)
|
||||
@@ -24,6 +25,9 @@ type CandidatePair struct {
|
||||
iceRoleControlling bool
|
||||
Remote Candidate
|
||||
Local Candidate
|
||||
latency time.Duration
|
||||
lastBindingRequest time.Time
|
||||
lastBindingTransactionID [12]byte
|
||||
bindingRequestCount uint16
|
||||
state CandidatePairState
|
||||
nominated bool
|
||||
@@ -100,3 +104,20 @@ func (a *Agent) sendSTUN(msg *stun.Message, local, remote Candidate) {
|
||||
a.log.Tracef("Failed to send STUN message: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *CandidatePair) markBindingRequest(transactionID [12]byte) {
|
||||
p.lastBindingRequest = time.Now()
|
||||
p.lastBindingTransactionID = transactionID
|
||||
}
|
||||
|
||||
func (p *CandidatePair) markBindingResponse(transactionID [12]byte) {
|
||||
if p.lastBindingRequest.IsZero() || transactionID != p.lastBindingTransactionID {
|
||||
return
|
||||
}
|
||||
|
||||
p.latency = time.Since(p.lastBindingRequest)
|
||||
}
|
||||
|
||||
func (p *CandidatePair) Latency() time.Duration {
|
||||
return p.latency
|
||||
}
|
||||
|
||||
@@ -139,6 +139,9 @@ func (s *controllingSelector) HandleSuccessResponse(m *stun.Message, local, remo
|
||||
return
|
||||
}
|
||||
|
||||
p.markBindingResponse(m.TransactionID)
|
||||
s.agent.onSuccessfulBindingResponse(p)
|
||||
|
||||
p.state = CandidatePairStateSucceeded
|
||||
s.log.Tracef("Found valid candidate pair: %s", p)
|
||||
if pendingRequest.isUseCandidate && s.agent.getSelectedPair() == nil {
|
||||
@@ -230,6 +233,9 @@ func (s *controlledSelector) HandleSuccessResponse(m *stun.Message, local, remot
|
||||
return
|
||||
}
|
||||
|
||||
p.markBindingResponse(m.TransactionID)
|
||||
s.agent.onSuccessfulBindingResponse(p)
|
||||
|
||||
p.state = CandidatePairStateSucceeded
|
||||
s.log.Tracef("Found valid candidate pair: %s", p)
|
||||
if p.nominateOnBindingSuccess {
|
||||
|
||||
Reference in New Issue
Block a user