use binding requests to calculate latency for each candidate pair

This commit is contained in:
Pascal Fischer
2024-03-15 18:20:59 +01:00
parent cb8a47ac37
commit bc851c5284
4 changed files with 49 additions and 4 deletions
+10 -4
View File
@@ -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 {
+12
View File
@@ -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)
+21
View File
@@ -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
}
+6
View File
@@ -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 {