2024-05-15 23:15:00 +00:00
|
|
|
// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
package ice
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
import "sync"
|
|
|
|
|
2024-05-15 23:15:00 +00:00
|
|
|
// OnConnectionStateChange sets a handler that is fired when the connection state changes
|
|
|
|
func (a *Agent) OnConnectionStateChange(f func(ConnectionState)) error {
|
|
|
|
a.onConnectionStateChangeHdlr.Store(f)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnSelectedCandidatePairChange sets a handler that is fired when the final candidate
|
|
|
|
// pair is selected
|
|
|
|
func (a *Agent) OnSelectedCandidatePairChange(f func(Candidate, Candidate)) error {
|
|
|
|
a.onSelectedCandidatePairChangeHdlr.Store(f)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// OnCandidate sets a handler that is fired when new candidates gathered. When
|
|
|
|
// the gathering process complete the last candidate is nil.
|
|
|
|
func (a *Agent) OnCandidate(f func(Candidate)) error {
|
|
|
|
a.onCandidateHdlr.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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Agent) onCandidate(c Candidate) {
|
|
|
|
if onCandidateHdlr, ok := a.onCandidateHdlr.Load().(func(Candidate)); ok {
|
|
|
|
onCandidateHdlr(c)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (a *Agent) onConnectionStateChange(s ConnectionState) {
|
|
|
|
if hdlr, ok := a.onConnectionStateChangeHdlr.Load().(func(ConnectionState)); ok {
|
|
|
|
hdlr(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
type handlerNotifier struct {
|
|
|
|
sync.Mutex
|
2024-10-10 11:33:36 +00:00
|
|
|
running bool
|
|
|
|
notifiers sync.WaitGroup
|
2024-07-11 19:34:20 +00:00
|
|
|
|
|
|
|
connectionStates []ConnectionState
|
|
|
|
connectionStateFunc func(ConnectionState)
|
|
|
|
|
|
|
|
candidates []Candidate
|
|
|
|
candidateFunc func(Candidate)
|
|
|
|
|
|
|
|
selectedCandidatePairs []*CandidatePair
|
|
|
|
candidatePairFunc func(*CandidatePair)
|
2024-10-10 11:33:36 +00:00
|
|
|
|
|
|
|
// State for closing
|
|
|
|
done chan struct{}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (h *handlerNotifier) Close(graceful bool) {
|
|
|
|
if graceful {
|
|
|
|
// if we were closed ungracefully before, we now
|
|
|
|
// want ot wait.
|
|
|
|
defer h.notifiers.Wait()
|
|
|
|
}
|
|
|
|
|
|
|
|
h.Lock()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-h.done:
|
|
|
|
h.Unlock()
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
close(h.done)
|
|
|
|
h.Unlock()
|
2024-07-11 19:34:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *handlerNotifier) EnqueueConnectionState(s ConnectionState) {
|
|
|
|
h.Lock()
|
|
|
|
defer h.Unlock()
|
|
|
|
|
2024-10-10 11:33:36 +00:00
|
|
|
select {
|
|
|
|
case <-h.done:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
notify := func() {
|
2024-10-10 11:33:36 +00:00
|
|
|
defer h.notifiers.Done()
|
2024-07-11 19:34:20 +00:00
|
|
|
for {
|
|
|
|
h.Lock()
|
|
|
|
if len(h.connectionStates) == 0 {
|
|
|
|
h.running = false
|
|
|
|
h.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
notification := h.connectionStates[0]
|
|
|
|
h.connectionStates = h.connectionStates[1:]
|
|
|
|
h.Unlock()
|
|
|
|
h.connectionStateFunc(notification)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h.connectionStates = append(h.connectionStates, s)
|
|
|
|
if !h.running {
|
|
|
|
h.running = true
|
2024-10-10 11:33:36 +00:00
|
|
|
h.notifiers.Add(1)
|
2024-07-11 19:34:20 +00:00
|
|
|
go notify()
|
2024-05-15 23:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
func (h *handlerNotifier) EnqueueCandidate(c Candidate) {
|
|
|
|
h.Lock()
|
|
|
|
defer h.Unlock()
|
|
|
|
|
2024-10-10 11:33:36 +00:00
|
|
|
select {
|
|
|
|
case <-h.done:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
notify := func() {
|
2024-10-10 11:33:36 +00:00
|
|
|
defer h.notifiers.Done()
|
2024-07-11 19:34:20 +00:00
|
|
|
for {
|
|
|
|
h.Lock()
|
|
|
|
if len(h.candidates) == 0 {
|
|
|
|
h.running = false
|
|
|
|
h.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
notification := h.candidates[0]
|
|
|
|
h.candidates = h.candidates[1:]
|
|
|
|
h.Unlock()
|
|
|
|
h.candidateFunc(notification)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h.candidates = append(h.candidates, c)
|
|
|
|
if !h.running {
|
|
|
|
h.running = true
|
2024-10-10 11:33:36 +00:00
|
|
|
h.notifiers.Add(1)
|
2024-07-11 19:34:20 +00:00
|
|
|
go notify()
|
2024-05-15 23:15:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
func (h *handlerNotifier) EnqueueSelectedCandidatePair(p *CandidatePair) {
|
|
|
|
h.Lock()
|
|
|
|
defer h.Unlock()
|
|
|
|
|
2024-10-10 11:33:36 +00:00
|
|
|
select {
|
|
|
|
case <-h.done:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
}
|
|
|
|
|
2024-07-11 19:34:20 +00:00
|
|
|
notify := func() {
|
2024-10-10 11:33:36 +00:00
|
|
|
defer h.notifiers.Done()
|
2024-07-11 19:34:20 +00:00
|
|
|
for {
|
|
|
|
h.Lock()
|
|
|
|
if len(h.selectedCandidatePairs) == 0 {
|
|
|
|
h.running = false
|
|
|
|
h.Unlock()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
notification := h.selectedCandidatePairs[0]
|
|
|
|
h.selectedCandidatePairs = h.selectedCandidatePairs[1:]
|
|
|
|
h.Unlock()
|
|
|
|
h.candidatePairFunc(notification)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
h.selectedCandidatePairs = append(h.selectedCandidatePairs, p)
|
|
|
|
if !h.running {
|
|
|
|
h.running = true
|
2024-10-10 11:33:36 +00:00
|
|
|
h.notifiers.Add(1)
|
2024-07-11 19:34:20 +00:00
|
|
|
go notify()
|
2024-05-15 23:15:00 +00:00
|
|
|
}
|
|
|
|
}
|