Skip to content

Commit

Permalink
Add ICE Trickle support
Browse files Browse the repository at this point in the history
Resolves pion/ice#51

Co-authored-by: Konstantin Itskov <konstantin.itskov@kovits.com>
  • Loading branch information
Sean-Der and trivigy committed May 30, 2019
1 parent 5e6149d commit 0ae5654
Show file tree
Hide file tree
Showing 7 changed files with 210 additions and 125 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ go 1.12
require (
github.com/pion/datachannel v1.4.3
github.com/pion/dtls v1.3.5
github.com/pion/ice v0.3.2
github.com/pion/ice v0.3.3
github.com/pion/logging v0.2.1
github.com/pion/quic v0.1.1
github.com/pion/rtcp v1.2.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ github.com/pion/datachannel v1.4.3 h1:tqS6YiqqAiFCxGGhvn1K7fHEzemK9Aov025dE/isGF
github.com/pion/datachannel v1.4.3/go.mod h1:SpMJbuu8v+qbA94m6lWQwSdCf8JKQvgmdSHDNtcbe+w=
github.com/pion/dtls v1.3.5 h1:mBioifvh6JSE9pD4FtJh5WoizygoqkOJNJyS5Ns+y1U=
github.com/pion/dtls v1.3.5/go.mod h1:CjlPLfQdsTg3G4AEXjJp8FY5bRweBlxHrgoFrN+fQsk=
github.com/pion/ice v0.3.2 h1:wBm0F9an2y+mpIlmn2sC4sHVjZnCl0K9zY23R3ijYmA=
github.com/pion/ice v0.3.2/go.mod h1:T57BaxW8oBC+CuV1+ZAAVm8/UsnpQB/S/hII+Y2Nyn0=
github.com/pion/ice v0.3.3 h1:ysSx7pDczIJx8XyYpFI2zoqtYhFD+B1cQdtY2ol5lT4=
github.com/pion/ice v0.3.3/go.mod h1:T57BaxW8oBC+CuV1+ZAAVm8/UsnpQB/S/hII+Y2Nyn0=
github.com/pion/logging v0.2.1 h1:LwASkBKZ+2ysGJ+jLv1E/9H1ge0k1nTfi1X+5zirkDk=
github.com/pion/logging v0.2.1/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
github.com/pion/quic v0.1.1 h1:D951FV+TOqI9A0rTF7tHx0Loooqz+nyzjEyj8o3PuMA=
Expand Down
121 changes: 99 additions & 22 deletions icegatherer.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,20 @@ type ICEGatherer struct {

validatedServers []*ice.URL

agent *ice.Agent
agentIsTrickle bool
agent *ice.Agent

portMin uint16
portMax uint16
candidateTypes []ice.CandidateType
connectionTimeout *time.Duration
keepaliveInterval *time.Duration
loggerFactory logging.LoggerFactory
log logging.LeveledLogger
networkTypes []NetworkType

onLocalCandidateHdlr func(candidate *ICECandidate)
onStateChangeHdlr func(state ICEGathererState)
}

// NewICEGatherer creates a new NewICEGatherer.
Expand Down Expand Up @@ -66,24 +71,27 @@ func NewICEGatherer(
connectionTimeout: connectionTimeout,
keepaliveInterval: keepaliveInterval,
loggerFactory: loggerFactory,
log: loggerFactory.NewLogger("ice"),
networkTypes: networkTypes,
candidateTypes: candidateTypes,
}, nil
}

// State indicates the current state of the ICE gatherer.
func (g *ICEGatherer) State() ICEGathererState {
g.lock.RLock()
defer g.lock.RUnlock()
return g.state
}

// Gather ICE candidates.
func (g *ICEGatherer) Gather() error {
func (g *ICEGatherer) createAgent() error {
g.lock.Lock()
defer g.lock.Unlock()
agentIsTrickle := g.onLocalCandidateHdlr != nil || g.onStateChangeHdlr != nil

if g.agent != nil {
if !g.agentIsTrickle && agentIsTrickle {
return errors.New("ICEAgent created without OnCandidate or StateChange handler, but now has one set")
}

return nil
}

config := &ice.AgentConfig{
Trickle: agentIsTrickle,
Urls: g.validatedServers,
PortMin: g.portMin,
PortMax: g.portMax,
Expand All @@ -108,11 +116,49 @@ func (g *ICEGatherer) Gather() error {
}

g.agent = agent
g.state = ICEGathererStateComplete
g.agentIsTrickle = agentIsTrickle
if agentIsTrickle {
g.state = ICEGathererStateComplete
}

return nil
}

// Gather ICE candidates.
func (g *ICEGatherer) Gather() error {
if err := g.createAgent(); err != nil {
return err
}

g.lock.Lock()
onLocalCandidateHdlr := g.onLocalCandidateHdlr
isTrickle := g.agentIsTrickle
agent := g.agent
g.lock.Unlock()

if !isTrickle {
return nil
}

g.setState(ICEGathererStateGathering)
if err := agent.OnCandidate(func(candidate ice.Candidate) {
if candidate != nil {
c, err := newICECandidateFromICE(candidate)
if err != nil {
g.log.Warnf("Failed to convert ice.Candidate: %s", err)
return
}
onLocalCandidateHdlr(&c)
} else {
g.setState(ICEGathererStateComplete)
onLocalCandidateHdlr(nil)
}
}); err != nil {
return err
}
return agent.GatherCandidates()
}

// Close prunes all local candidates, and closes the ports.
func (g *ICEGatherer) Close() error {
g.lock.Lock()
Expand All @@ -133,14 +179,11 @@ func (g *ICEGatherer) Close() error {

// GetLocalParameters returns the ICE parameters of the ICEGatherer.
func (g *ICEGatherer) GetLocalParameters() (ICEParameters, error) {
g.lock.RLock()
defer g.lock.RUnlock()
if g.agent == nil {
return ICEParameters{}, errors.New("gatherer not started")
if err := g.createAgent(); err != nil {
return ICEParameters{}, err
}

frag, pwd := g.agent.GetLocalUserCredentials()

return ICEParameters{
UsernameFragment: frag,
Password: pwd,
Expand All @@ -150,17 +193,51 @@ func (g *ICEGatherer) GetLocalParameters() (ICEParameters, error) {

// GetLocalCandidates returns the sequence of valid local candidates associated with the ICEGatherer.
func (g *ICEGatherer) GetLocalCandidates() ([]ICECandidate, error) {
g.lock.RLock()
defer g.lock.RUnlock()

if g.agent == nil {
return nil, errors.New("gatherer not started")
if err := g.createAgent(); err != nil {
return nil, err
}

iceCandidates, err := g.agent.GetLocalCandidates()
if err != nil {
return nil, err
}

return newICECandidatesFromICE(iceCandidates)
}

// OnLocalCandidate sets an event handler which fires when a new local ICE candidate is available
func (g *ICEGatherer) OnLocalCandidate(f func(*ICECandidate)) {
g.lock.Lock()
defer g.lock.Unlock()
g.onLocalCandidateHdlr = f
}

// OnStateChange fires any time the ICEGatherer changes
func (g *ICEGatherer) OnStateChange(f func(ICEGathererState)) {
g.lock.Lock()
defer g.lock.Unlock()
g.onStateChangeHdlr = f
}

// State indicates the current state of the ICE gatherer.
func (g *ICEGatherer) State() ICEGathererState {
g.lock.RLock()
defer g.lock.RUnlock()
return g.state
}

func (g *ICEGatherer) setState(s ICEGathererState) {
g.lock.Lock()
g.state = s
hdlr := g.onStateChangeHdlr
g.lock.Unlock()

if hdlr != nil {
go hdlr(s)
}
}

func (g *ICEGatherer) getAgent() *ice.Agent {
g.lock.RLock()
defer g.lock.RUnlock()
return g.agent
}
3 changes: 1 addition & 2 deletions icetransport.go
Original file line number Diff line number Diff line change
Expand Up @@ -260,8 +260,7 @@ func (t *ICETransport) NewEndpoint(f mux.MatchFunc) *mux.Endpoint {
}

func (t *ICETransport) ensureGatherer() error {
if t.gatherer == nil ||
t.gatherer.agent == nil {
if t.gatherer == nil || t.gatherer.getAgent() == nil {
return errors.New("gatherer not started")
}

Expand Down
Loading

0 comments on commit 0ae5654

Please sign in to comment.