Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8b33e86

Browse files
committed
Lock adding ICE candidate
1 parent b6003c7 commit 8b33e86

File tree

1 file changed

+52
-28
lines changed

1 file changed

+52
-28
lines changed

peer/conn.go

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ func newWithClientOrServer(servers []webrtc.ICEServer, client bool, opts *ConnOp
7979
// This channel needs to be bufferred otherwise slow consumers
8080
// of this will cause a connection failure.
8181
localCandidateChannel: make(chan webrtc.ICECandidateInit, 16),
82-
pendingCandidates: make([]webrtc.ICECandidateInit, 0),
82+
pendingCandidatesToSend: make([]webrtc.ICECandidateInit, 0),
83+
pendingCandidatesToAccept: make([]webrtc.ICECandidateInit, 0),
8384
localSessionDescriptionChannel: make(chan webrtc.SessionDescription, 1),
8485
remoteSessionDescriptionChannel: make(chan webrtc.SessionDescription, 1),
8586
}
@@ -129,8 +130,11 @@ type Conn struct {
129130
localSessionDescriptionChannel chan webrtc.SessionDescription
130131
remoteSessionDescriptionChannel chan webrtc.SessionDescription
131132

132-
pendingCandidates []webrtc.ICECandidateInit
133-
pendingCandidatesMutex sync.Mutex
133+
pendingCandidatesToSend []webrtc.ICECandidateInit
134+
pendingCandidatesToSendMutex sync.Mutex
135+
136+
pendingCandidatesToAccept []webrtc.ICECandidateInit
137+
pendingCandidatesToAcceptMutex sync.Mutex
134138

135139
pingChannelID uint16
136140
pingEchoChannelID uint16
@@ -170,19 +174,19 @@ func (c *Conn) init() error {
170174
if iceCandidate == nil {
171175
return
172176
}
173-
c.pendingCandidatesMutex.Lock()
174-
defer c.pendingCandidatesMutex.Unlock()
177+
c.pendingCandidatesToSendMutex.Lock()
178+
defer c.pendingCandidatesToSendMutex.Unlock()
175179
json := iceCandidate.ToJSON()
176180
fields := []slog.Field{
177181
slog.F("hash", c.hashCandidate(json)),
178182
slog.F("length", len(json.Candidate)),
179183
}
180184
if c.rtc.RemoteDescription() == nil {
181-
c.pendingCandidates = append(c.pendingCandidates, json)
182-
c.opts.Logger.Debug(context.Background(), "buffering candidate", fields...)
185+
c.pendingCandidatesToSend = append(c.pendingCandidatesToSend, json)
186+
c.opts.Logger.Debug(context.Background(), "buffering local candidate to send", fields...)
183187
return
184188
}
185-
c.opts.Logger.Debug(context.Background(), "sending candidate directly", fields...)
189+
c.opts.Logger.Debug(context.Background(), "sending local candidate directly", fields...)
186190
select {
187191
case <-c.closed:
188192
break
@@ -357,10 +361,6 @@ func (c *Conn) negotiate() {
357361
return
358362
}
359363

360-
if c.offerrer {
361-
c.flushPendingCandidates()
362-
}
363-
364364
if !c.offerrer {
365365
answer, err := c.rtc.CreateAnswer(&webrtc.AnswerOptions{})
366366
if err != nil {
@@ -384,16 +384,12 @@ func (c *Conn) negotiate() {
384384
return
385385
case c.localSessionDescriptionChannel <- answer:
386386
}
387-
388-
c.flushPendingCandidates()
389387
}
390-
}
391388

392-
func (c *Conn) flushPendingCandidates() {
393-
c.pendingCandidatesMutex.Lock()
394-
defer c.pendingCandidatesMutex.Unlock()
395-
for _, pendingCandidate := range c.pendingCandidates {
396-
c.opts.Logger.Debug(context.Background(), "sending buffered remote candidate",
389+
c.pendingCandidatesToSendMutex.Lock()
390+
defer c.pendingCandidatesToSendMutex.Unlock()
391+
for _, pendingCandidate := range c.pendingCandidatesToSend {
392+
c.opts.Logger.Debug(context.Background(), "sending buffered local candidate",
397393
slog.F("hash", c.hashCandidate(pendingCandidate)),
398394
slog.F("length", len(pendingCandidate.Candidate)),
399395
)
@@ -403,10 +399,28 @@ func (c *Conn) flushPendingCandidates() {
403399
case c.localCandidateChannel <- pendingCandidate:
404400
}
405401
}
402+
c.opts.Logger.Debug(context.Background(), "flushed buffered local candidates",
403+
slog.F("count", len(c.pendingCandidatesToSend)),
404+
)
405+
c.pendingCandidatesToSend = make([]webrtc.ICECandidateInit, 0)
406+
407+
c.pendingCandidatesToAcceptMutex.Lock()
408+
defer c.pendingCandidatesToAcceptMutex.Unlock()
409+
for _, pendingCandidate := range c.pendingCandidatesToAccept {
410+
c.opts.Logger.Debug(context.Background(), "adding buffered remote candidate",
411+
slog.F("hash", c.hashCandidate(pendingCandidate)),
412+
slog.F("length", len(pendingCandidate.Candidate)),
413+
)
414+
err = c.rtc.AddICECandidate(pendingCandidate)
415+
if err != nil {
416+
_ = c.CloseWithError(xerrors.Errorf("accept buffered remote candidate: %w", err))
417+
return
418+
}
419+
}
406420
c.opts.Logger.Debug(context.Background(), "flushed buffered remote candidates",
407-
slog.F("count", len(c.pendingCandidates)),
421+
slog.F("count", len(c.pendingCandidatesToAccept)),
408422
)
409-
c.pendingCandidates = make([]webrtc.ICECandidateInit, 0)
423+
c.pendingCandidatesToAccept = make([]webrtc.ICECandidateInit, 0)
410424
}
411425

412426
// LocalCandidate returns a channel that emits when a local candidate
@@ -416,12 +430,22 @@ func (c *Conn) LocalCandidate() <-chan webrtc.ICECandidateInit {
416430
}
417431

418432
// AddRemoteCandidate adds a remote candidate to the RTC connection.
419-
func (c *Conn) AddRemoteCandidate(i webrtc.ICECandidateInit) error {
420-
c.opts.Logger.Debug(context.Background(), "accepting candidate",
421-
slog.F("hash", c.hashCandidate(i)),
422-
slog.F("length", len(i.Candidate)),
423-
)
424-
return c.rtc.AddICECandidate(i)
433+
func (c *Conn) AddRemoteCandidate(iceCandidate webrtc.ICECandidateInit) error {
434+
c.pendingCandidatesToAcceptMutex.Lock()
435+
defer c.pendingCandidatesToAcceptMutex.Unlock()
436+
fields := []slog.Field{
437+
slog.F("hash", c.hashCandidate(iceCandidate)),
438+
slog.F("length", len(iceCandidate.Candidate)),
439+
}
440+
// The consumer doesn't need to set the session description before
441+
// adding remote candidates. This buffers it so an error doesn't occur.
442+
if c.rtc.RemoteDescription() == nil {
443+
c.opts.Logger.Debug(context.Background(), "buffering remote candidate to accept", fields...)
444+
c.pendingCandidatesToAccept = append(c.pendingCandidatesToAccept, iceCandidate)
445+
return nil
446+
}
447+
c.opts.Logger.Debug(context.Background(), "adding remote candidate", fields...)
448+
return c.rtc.AddICECandidate(iceCandidate)
425449
}
426450

427451
// LocalSessionDescription returns a channel that emits a session description

0 commit comments

Comments
 (0)