@@ -62,17 +62,19 @@ func newWithClientOrServer(servers []webrtc.ICEServer, client bool, opts *ConnOp
62
62
return nil , xerrors .Errorf ("create peer connection: %w" , err )
63
63
}
64
64
conn := & Conn {
65
- pingChannelID : 1 ,
66
- pingEchoChannelID : 2 ,
67
- opts : opts ,
68
- rtc : rtc ,
69
- offerrer : client ,
70
- closed : make (chan struct {}),
71
- dcOpenChannel : make (chan * webrtc.DataChannel ),
72
- dcDisconnectChannel : make (chan struct {}),
73
- dcFailedChannel : make (chan struct {}),
74
- localCandidateChannel : make (chan webrtc.ICECandidateInit ),
75
- pendingCandidates : make ([]webrtc.ICECandidateInit , 0 ),
65
+ pingChannelID : 1 ,
66
+ pingEchoChannelID : 2 ,
67
+ opts : opts ,
68
+ rtc : rtc ,
69
+ offerrer : client ,
70
+ closed : make (chan struct {}),
71
+ dcOpenChannel : make (chan * webrtc.DataChannel ),
72
+ dcDisconnectChannel : make (chan struct {}),
73
+ dcFailedChannel : make (chan struct {}),
74
+ // This channel needs to be bufferred otherwise slow consumers
75
+ // of this will cause a connection failure.
76
+ localCandidateChannel : make (chan webrtc.ICECandidateInit , 16 ),
77
+ pendingRemoteCandidates : make ([]webrtc.ICECandidateInit , 0 ),
76
78
localSessionDescriptionChannel : make (chan webrtc.SessionDescription ),
77
79
remoteSessionDescriptionChannel : make (chan webrtc.SessionDescription ),
78
80
}
@@ -120,7 +122,7 @@ type Conn struct {
120
122
localSessionDescriptionChannel chan webrtc.SessionDescription
121
123
remoteSessionDescriptionChannel chan webrtc.SessionDescription
122
124
123
- pendingCandidates []webrtc.ICECandidateInit
125
+ pendingRemoteCandidates []webrtc.ICECandidateInit
124
126
pendingCandidatesMutex sync.Mutex
125
127
pendingCandidatesFlushed bool
126
128
@@ -142,14 +144,6 @@ func (c *Conn) init() error {
142
144
if iceCandidate == nil {
143
145
return
144
146
}
145
- c .pendingCandidatesMutex .Lock ()
146
- defer c .pendingCandidatesMutex .Unlock ()
147
-
148
- if ! c .pendingCandidatesFlushed {
149
- c .opts .Logger .Debug (context .Background (), "adding local candidate to buffer" )
150
- c .pendingCandidates = append (c .pendingCandidates , iceCandidate .ToJSON ())
151
- return
152
- }
153
147
c .opts .Logger .Debug (context .Background (), "adding local candidate" )
154
148
select {
155
149
case <- c .closed :
@@ -262,6 +256,7 @@ func (c *Conn) negotiate() {
262
256
_ = c .CloseWithError (xerrors .Errorf ("create offer: %w" , err ))
263
257
return
264
258
}
259
+ c .opts .Logger .Debug (context .Background (), "setting local description" )
265
260
err = c .rtc .SetLocalDescription (offer )
266
261
if err != nil {
267
262
_ = c .CloseWithError (xerrors .Errorf ("set local description: %w" , err ))
@@ -281,25 +276,20 @@ func (c *Conn) negotiate() {
281
276
case remoteDescription = <- c .remoteSessionDescriptionChannel :
282
277
}
283
278
279
+ c .opts .Logger .Debug (context .Background (), "setting remote description" )
284
280
err := c .rtc .SetRemoteDescription (remoteDescription )
285
281
if err != nil {
286
- c .pendingCandidatesMutex .Unlock ()
287
282
_ = c .CloseWithError (xerrors .Errorf ("set remote description (closed %v): %w" , c .isClosed (), err ))
288
283
return
289
284
}
290
285
291
- if c .offerrer {
292
- // ICE candidates reset when an offer/answer is set for the first
293
- // time. If candidates flush before this point, a connection could fail.
294
- c .flushPendingCandidates ()
295
- }
296
-
297
286
if ! c .offerrer {
298
287
answer , err := c .rtc .CreateAnswer (& webrtc.AnswerOptions {})
299
288
if err != nil {
300
289
_ = c .CloseWithError (xerrors .Errorf ("create answer: %w" , err ))
301
290
return
302
291
}
292
+ c .opts .Logger .Debug (context .Background (), "setting local description" )
303
293
err = c .rtc .SetLocalDescription (answer )
304
294
if err != nil {
305
295
_ = c .CloseWithError (xerrors .Errorf ("set local description: %w" , err ))
@@ -313,28 +303,23 @@ func (c *Conn) negotiate() {
313
303
return
314
304
case c .localSessionDescriptionChannel <- answer :
315
305
}
316
-
317
- // Wait until the local description is set to flush candidates.
318
- c .flushPendingCandidates ()
319
306
}
320
- }
321
307
322
- // flushPendingCandidates writes all local candidates to the candidate send channel .
323
- // The localCandidateChannel is expected to be serviced, otherwise this could block.
324
- func ( c * Conn ) flushPendingCandidates () {
308
+ // The ICE transport resets when the remote description is updated .
309
+ // Adding ICE candidates before this point causes a failed connection,
310
+ // because the candidate would be lost.
325
311
c .pendingCandidatesMutex .Lock ()
326
312
defer c .pendingCandidatesMutex .Unlock ()
327
- for _ , pendingCandidate := range c .pendingCandidates {
328
- c .opts .Logger .Debug (context .Background (), "flushing local candidate" )
329
- select {
330
- case <- c .closed :
313
+ for _ , pendingCandidate := range c .pendingRemoteCandidates {
314
+ c .opts .Logger .Debug (context .Background (), "flushing remote candidate" )
315
+ err := c .rtc .AddICECandidate (pendingCandidate )
316
+ if err != nil {
317
+ _ = c .CloseWithError (xerrors .Errorf ("flush pending candidates: %w" , err ))
331
318
return
332
- case c .localCandidateChannel <- pendingCandidate :
333
319
}
334
320
}
335
- c .pendingCandidates = make ([]webrtc.ICECandidateInit , 0 )
336
321
c .pendingCandidatesFlushed = true
337
- c .opts .Logger .Debug (context .Background (), "flushed candidates" )
322
+ c .opts .Logger .Debug (context .Background (), "flushed remote candidates" )
338
323
}
339
324
340
325
// LocalCandidate returns a channel that emits when a local candidate
@@ -345,6 +330,13 @@ func (c *Conn) LocalCandidate() <-chan webrtc.ICECandidateInit {
345
330
346
331
// AddRemoteCandidate adds a remote candidate to the RTC connection.
347
332
func (c * Conn ) AddRemoteCandidate (i webrtc.ICECandidateInit ) error {
333
+ c .pendingCandidatesMutex .Lock ()
334
+ defer c .pendingCandidatesMutex .Unlock ()
335
+ if ! c .pendingCandidatesFlushed {
336
+ c .opts .Logger .Debug (context .Background (), "adding remote candidate to buffer" )
337
+ c .pendingRemoteCandidates = append (c .pendingRemoteCandidates , i )
338
+ return nil
339
+ }
348
340
c .opts .Logger .Debug (context .Background (), "adding remote candidate" )
349
341
return c .rtc .AddICECandidate (i )
350
342
}
0 commit comments