@@ -79,7 +79,8 @@ 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
- pendingCandidates : make ([]webrtc.ICECandidateInit , 0 ),
82
+ pendingCandidatesToSend : make ([]webrtc.ICECandidateInit , 0 ),
83
+ pendingCandidatesToAccept : make ([]webrtc.ICECandidateInit , 0 ),
83
84
localSessionDescriptionChannel : make (chan webrtc.SessionDescription , 1 ),
84
85
remoteSessionDescriptionChannel : make (chan webrtc.SessionDescription , 1 ),
85
86
}
@@ -129,8 +130,11 @@ type Conn struct {
129
130
localSessionDescriptionChannel chan webrtc.SessionDescription
130
131
remoteSessionDescriptionChannel chan webrtc.SessionDescription
131
132
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
134
138
135
139
pingChannelID uint16
136
140
pingEchoChannelID uint16
@@ -170,19 +174,19 @@ func (c *Conn) init() error {
170
174
if iceCandidate == nil {
171
175
return
172
176
}
173
- c .pendingCandidatesMutex .Lock ()
174
- defer c .pendingCandidatesMutex .Unlock ()
177
+ c .pendingCandidatesToSendMutex .Lock ()
178
+ defer c .pendingCandidatesToSendMutex .Unlock ()
175
179
json := iceCandidate .ToJSON ()
176
180
fields := []slog.Field {
177
181
slog .F ("hash" , c .hashCandidate (json )),
178
182
slog .F ("length" , len (json .Candidate )),
179
183
}
180
184
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 ... )
183
187
return
184
188
}
185
- c .opts .Logger .Debug (context .Background (), "sending candidate directly" , fields ... )
189
+ c .opts .Logger .Debug (context .Background (), "sending local candidate directly" , fields ... )
186
190
select {
187
191
case <- c .closed :
188
192
break
@@ -357,10 +361,6 @@ func (c *Conn) negotiate() {
357
361
return
358
362
}
359
363
360
- if c .offerrer {
361
- c .flushPendingCandidates ()
362
- }
363
-
364
364
if ! c .offerrer {
365
365
answer , err := c .rtc .CreateAnswer (& webrtc.AnswerOptions {})
366
366
if err != nil {
@@ -384,16 +384,12 @@ func (c *Conn) negotiate() {
384
384
return
385
385
case c .localSessionDescriptionChannel <- answer :
386
386
}
387
-
388
- c .flushPendingCandidates ()
389
387
}
390
- }
391
388
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" ,
397
393
slog .F ("hash" , c .hashCandidate (pendingCandidate )),
398
394
slog .F ("length" , len (pendingCandidate .Candidate )),
399
395
)
@@ -403,10 +399,28 @@ func (c *Conn) flushPendingCandidates() {
403
399
case c .localCandidateChannel <- pendingCandidate :
404
400
}
405
401
}
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
+ }
406
420
c .opts .Logger .Debug (context .Background (), "flushed buffered remote candidates" ,
407
- slog .F ("count" , len (c .pendingCandidates )),
421
+ slog .F ("count" , len (c .pendingCandidatesToAccept )),
408
422
)
409
- c .pendingCandidates = make ([]webrtc.ICECandidateInit , 0 )
423
+ c .pendingCandidatesToAccept = make ([]webrtc.ICECandidateInit , 0 )
410
424
}
411
425
412
426
// LocalCandidate returns a channel that emits when a local candidate
@@ -416,12 +430,22 @@ func (c *Conn) LocalCandidate() <-chan webrtc.ICECandidateInit {
416
430
}
417
431
418
432
// 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 )
425
449
}
426
450
427
451
// LocalSessionDescription returns a channel that emits a session description
0 commit comments