@@ -79,6 +79,7 @@ func newWithClientOrServer(servers []webrtc.ICEServer, client bool, opts *ConnOp
79
79
// This channel needs to be bufferred otherwise slow consumers
80
80
// of this will cause a connection failure.
81
81
localCandidateChannel : make (chan webrtc.ICECandidateInit , 16 ),
82
+ pendingRemoteCandidates : make ([]webrtc.ICECandidateInit , 0 ),
82
83
localSessionDescriptionChannel : make (chan webrtc.SessionDescription , 1 ),
83
84
remoteSessionDescriptionChannel : make (chan webrtc.SessionDescription , 1 ),
84
85
}
@@ -128,6 +129,10 @@ type Conn struct {
128
129
localSessionDescriptionChannel chan webrtc.SessionDescription
129
130
remoteSessionDescriptionChannel chan webrtc.SessionDescription
130
131
132
+ pendingRemoteCandidates []webrtc.ICECandidateInit
133
+ pendingCandidatesMutex sync.Mutex
134
+ pendingCandidatesFlushed bool
135
+
131
136
pingChannelID uint16
132
137
pingEchoChannelID uint16
133
138
@@ -329,6 +334,28 @@ func (c *Conn) negotiate() {
329
334
return
330
335
}
331
336
337
+ // The RemoteDescription must be set before ICE candidates can be
338
+ // added to a WebRTC connection.
339
+ c .pendingCandidatesMutex .Lock ()
340
+ for _ , pendingCandidate := range c .pendingRemoteCandidates {
341
+ hash := sha256 .Sum224 ([]byte (pendingCandidate .Candidate ))
342
+ c .opts .Logger .Debug (context .Background (), "flushing buffered remote candidate" ,
343
+ slog .F ("hash" , hash ),
344
+ slog .F ("length" , len (pendingCandidate .Candidate )),
345
+ )
346
+ err := c .rtc .AddICECandidate (pendingCandidate )
347
+ if err != nil {
348
+ _ = c .CloseWithError (xerrors .Errorf ("flush pending remote candidate: %w" , err ))
349
+ return
350
+ }
351
+ }
352
+ c .opts .Logger .Debug (context .Background (), "flushed buffered remote candidates" ,
353
+ slog .F ("count" , len (c .pendingRemoteCandidates )),
354
+ )
355
+ c .pendingCandidatesFlushed = true
356
+ c .pendingRemoteCandidates = make ([]webrtc.ICECandidateInit , 0 )
357
+ c .pendingCandidatesMutex .Unlock ()
358
+
332
359
if ! c .offerrer {
333
360
answer , err := c .rtc .CreateAnswer (& webrtc.AnswerOptions {})
334
361
if err != nil {
@@ -362,10 +389,18 @@ func (c *Conn) LocalCandidate() <-chan webrtc.ICECandidateInit {
362
389
363
390
// AddRemoteCandidate adds a remote candidate to the RTC connection.
364
391
func (c * Conn ) AddRemoteCandidate (i webrtc.ICECandidateInit ) error {
365
- c .opts .Logger .Debug (context .Background (), "adding remote candidate" ,
392
+ c .pendingCandidatesMutex .Lock ()
393
+ defer c .pendingCandidatesMutex .Unlock ()
394
+ fields := []slog.Field {
366
395
slog .F ("hash" , c .hashCandidate (i )),
367
396
slog .F ("length" , len (i .Candidate )),
368
- )
397
+ }
398
+ if ! c .pendingCandidatesFlushed {
399
+ c .opts .Logger .Debug (context .Background (), "bufferring remote candidate" , fields ... )
400
+ c .pendingRemoteCandidates = append (c .pendingRemoteCandidates , i )
401
+ return nil
402
+ }
403
+ c .opts .Logger .Debug (context .Background (), "adding remote candidate" , fields ... )
369
404
return c .rtc .AddICECandidate (i )
370
405
}
371
406
0 commit comments