Fixes for pre-added recvonly transceivers

Which were previously unable to:

1. have a sending track set to them, or
2. receive a track after renegotiation.

I'm not 100% sure if this covers all cases where a track is added and
removed and then added again. BUT IIRC there was a change that did not
allow transceiver reuse after a track was removed from it. Again, not
100% sure.

Fixes #1722.
This commit is contained in:
Jerko Steiner
2021-03-20 08:51:14 +01:00
parent 07d7403cca
commit 6465248f1e
3 changed files with 92 additions and 2 deletions

View File

@@ -1044,7 +1044,8 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
}
}
if t == nil {
switch {
case t == nil:
receiver, err := pc.api.NewRTPReceiver(kind, pc.dtlsTransport)
if err != nil {
return err
@@ -1058,10 +1059,14 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
t = pc.newRTPTransceiver(receiver, nil, localDirection, kind)
pc.onNegotiationNeeded()
} else if direction == RTPTransceiverDirectionRecvonly {
case direction == RTPTransceiverDirectionRecvonly:
if t.Direction() == RTPTransceiverDirectionSendrecv {
t.setDirection(RTPTransceiverDirectionSendonly)
}
case direction == RTPTransceiverDirectionSendrecv:
if t.Direction() == RTPTransceiverDirectionSendonly {
t.setDirection(RTPTransceiverDirectionSendrecv)
}
}
if t.Mid() == "" {

View File

@@ -60,6 +60,85 @@ func sdpMidHasSsrc(offer SessionDescription, mid string, ssrc SSRC) bool {
return false
}
func TestPeerConnection_Renegotiation_AddRecvonlyTransceiver(t *testing.T) {
type testCase struct {
name string
answererSends bool
}
testCases := []testCase{
// Assert the following behaviors:
// - Offerer can add a recvonly transceiver
// - During negotiation, answerer peer adds an inactive (or sendonly) transceiver
// - Offerer can add a track
// - Answerer can receive the RTP packets.
{"add recvonly, then receive from answerer", false},
// Assert the following behaviors:
// - Offerer can add a recvonly transceiver
// - During negotiation, answerer peer adds an inactive (or sendonly) transceiver
// - Answerer can add a track to the existing sendonly transceiver
// - Offerer can receive the RTP packets.
{"add recvonly, then send to answerer", true},
}
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
lim := test.TimeOut(time.Second * 30)
defer lim.Stop()
report := test.CheckRoutines(t)
defer report()
pcOffer, pcAnswer, err := newPair()
if err != nil {
t.Fatal(err)
}
_, err = pcOffer.AddTransceiverFromKind(
RTPCodecTypeVideo,
RtpTransceiverInit{
Direction: RTPTransceiverDirectionRecvonly,
},
)
assert.NoError(t, err)
assert.NoError(t, signalPair(pcOffer, pcAnswer))
localTrack, err := NewTrackLocalStaticSample(
RTPCodecCapability{MimeType: "video/VP8"}, "track-one", "stream-one",
)
require.NoError(t, err)
if tc.answererSends {
_, err = pcAnswer.AddTrack(localTrack)
} else {
_, err = pcOffer.AddTrack(localTrack)
}
require.NoError(t, err)
onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
if tc.answererSends {
pcOffer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
onTrackFiredFunc()
})
} else {
pcAnswer.OnTrack(func(track *TrackRemote, r *RTPReceiver) {
onTrackFiredFunc()
})
}
assert.NoError(t, signalPair(pcOffer, pcAnswer))
sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{localTrack})
closePairNow(t, pcOffer, pcAnswer)
})
}
}
/*
* Assert the following behaviors
* - We are able to call AddTrack after signaling

View File

@@ -115,6 +115,12 @@ func (t *RTPTransceiver) setSendingTrack(track TrackLocal) error {
t.setDirection(RTPTransceiverDirectionSendonly)
case track == nil && t.Direction() == RTPTransceiverDirectionSendrecv:
t.setDirection(RTPTransceiverDirectionRecvonly)
case track != nil && t.Direction() == RTPTransceiverDirectionSendonly:
// Handle the case where a sendonly transceiver was added by a negotiation
// initiated by remote peer. For example a remote peer added a transceiver
// with direction recvonly.
case track != nil && t.Direction() == RTPTransceiverDirectionSendrecv:
// Similar to above, but for sendrecv transceiver.
case track == nil && t.Direction() == RTPTransceiverDirectionSendonly:
t.setDirection(RTPTransceiverDirectionInactive)
default: