Skip to content

Commit

Permalink
Reset state machine after negotiationNeededOp
Browse files Browse the repository at this point in the history
- Fixes #2774
  • Loading branch information
edaniels committed Jun 11, 2024
1 parent 09461d5 commit d2fd197
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 10 deletions.
20 changes: 10 additions & 10 deletions peerconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,16 @@ func (pc *PeerConnection) onNegotiationNeeded() {
}

func (pc *PeerConnection) negotiationNeededOp() {
// non-canon, reset needed state machine and run again if there was a request
defer func() {
pc.mu.Lock()
defer pc.mu.Unlock()
if pc.negotiationNeededState == negotiationNeededStateQueue {
defer pc.onNegotiationNeeded()
}
pc.negotiationNeededState = negotiationNeededStateEmpty
}()

// Don't run NegotiatedNeeded checks if OnNegotiationNeeded is not set
if handler, ok := pc.onNegotiationNeededHandler.Load().(func()); !ok || handler == nil {
return
Expand All @@ -307,16 +317,6 @@ func (pc *PeerConnection) negotiationNeededOp() {
return
}

// non-canon, run again if there was a request
defer func() {
pc.mu.Lock()
defer pc.mu.Unlock()
if pc.negotiationNeededState == negotiationNeededStateQueue {
defer pc.onNegotiationNeeded()
}
pc.negotiationNeededState = negotiationNeededStateEmpty
}()

// Step 2.3
if pc.SignalingState() != SignalingStateStable {
return
Expand Down
38 changes: 38 additions & 0 deletions peerconnection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,6 +553,44 @@ func TestNegotiationNeeded(t *testing.T) {
assert.NoError(t, pc.Close())
}

// See https://github.com/pion/webrtc/issues/2774
func TestNegotiationNeededAddedAfterOpQueueDone(t *testing.T) {
lim := test.TimeOut(time.Second * 30)
defer lim.Stop()

report := test.CheckRoutines(t)
defer report()

pc, err := NewPeerConnection(Configuration{})
if err != nil {
t.Error(err.Error())
}

var wg sync.WaitGroup
wg.Add(1)

_, err = pc.CreateDataChannel("initial_data_channel", nil)
assert.NoError(t, err)

// after there are no ops left in the queue, a previously faulty version
// of negotiationNeededOp would keep the negotiation needed state in
// negotiationNeededStateQueue which will cause all subsequent
// onNegotiationNeeded calls to never queue again, only if
// OnNegotiationNeeded has not been set yet.
for !pc.ops.IsEmpty() {
time.Sleep(time.Millisecond)
}

pc.OnNegotiationNeeded(wg.Done)

_, err = pc.CreateDataChannel("another_data_channel", nil)
assert.NoError(t, err)

wg.Wait()

assert.NoError(t, pc.Close())
}

func TestMultipleCreateChannel(t *testing.T) {
var wg sync.WaitGroup

Expand Down

0 comments on commit d2fd197

Please sign in to comment.