Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ice trickle support #691

Merged
merged 1 commit into from
May 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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