diff --git a/peerconnection.go b/peerconnection.go index a29e44fb796..ef61d9e0663 100644 --- a/peerconnection.go +++ b/peerconnection.go @@ -400,6 +400,14 @@ func (pc *PeerConnection) checkNegotiationNeeded() bool { //nolint:gocognit return true } track := sender.Track() + if track == nil { + // Situation when sender's track is nil could happen when + // a) replaceTrack(nil) is called + // b) removeTrack() is called, changing the transceiver's direction to inactive + // As t.Direction() in this branch is either sendrecv or sendonly, we believe (a) option is the case + // As calling replaceTrack does not require renegotiation, we skip check for this transceiver + continue + } if !okMsid || descMsid != track.StreamID()+" "+track.ID() { return true } diff --git a/peerconnection_renegotiation_test.go b/peerconnection_renegotiation_test.go index 6b52706d28e..35bd9a5debc 100644 --- a/peerconnection_renegotiation_test.go +++ b/peerconnection_renegotiation_test.go @@ -1323,3 +1323,29 @@ func TestNegotiationNeededWithRecvonlyTrack(t *testing.T) { closePairNow(t, pcOffer, pcAnswer) } + +func TestNegotiationNotNeededAfterReplaceTrackNil(t *testing.T) { + lim := test.TimeOut(time.Second * 30) + defer lim.Stop() + + report := test.CheckRoutines(t) + defer report() + + pcOffer, err := NewPeerConnection(Configuration{}) + assert.NoError(t, err) + + pcAnswer, err := NewPeerConnection(Configuration{}) + assert.NoError(t, err) + + tr, err := pcOffer.AddTransceiverFromKind(RTPCodecTypeAudio) + assert.NoError(t, err) + + assert.NoError(t, signalPair(pcOffer, pcAnswer)) + + assert.NoError(t, tr.Sender().ReplaceTrack(nil)) + + assert.False(t, pcOffer.checkNegotiationNeeded()) + + assert.NoError(t, pcOffer.Close()) + assert.NoError(t, pcAnswer.Close()) +}