Skip to content

Commit 37e16a3

Browse files
boks1971davidzhao
authored andcommitted
Bolting on send side simulcast
Introduces AddEncoding method in RTP sender to add simulcast encodings. Added UTs for AddEncoding. Also modified the Simulcast send test to use the new API.
1 parent e2b8d4c commit 37e16a3

File tree

8 files changed

+399
-101
lines changed

8 files changed

+399
-101
lines changed

errors.go

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ var (
142142
// ErrRTPSenderNewTrackHasIncorrectKind indicates that the new track is of a different kind than the previous/original
143143
ErrRTPSenderNewTrackHasIncorrectKind = errors.New("new track must be of the same kind as previous")
144144

145+
// ErrRTPSenderNewTrackHasIncorrectEnvelope indicates that the new track has a different envelope than the previous/original
146+
ErrRTPSenderNewTrackHasIncorrectEnvelope = errors.New("new track must have the same envelope as previous")
147+
145148
// ErrUnbindFailed indicates that a TrackLocal was not able to be unbind
146149
ErrUnbindFailed = errors.New("failed to unbind TrackLocal from PeerConnection")
147150

@@ -202,10 +205,16 @@ var (
202205
errRTPReceiverWithSSRCTrackStreamNotFound = errors.New("unable to find stream for Track with SSRC")
203206
errRTPReceiverForRIDTrackStreamNotFound = errors.New("no trackStreams found for RID")
204207

205-
errRTPSenderTrackNil = errors.New("Track must not be nil")
206-
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
207-
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
208-
errRTPSenderTrackRemoved = errors.New("Sender Track has been removed or replaced to nil")
208+
errRTPSenderTrackNil = errors.New("Track must not be nil")
209+
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
210+
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
211+
errRTPSenderStopped = errors.New("Sender has already been stopped")
212+
errRTPSenderTrackRemoved = errors.New("Sender Track has been removed or replaced to nil")
213+
errRTPSenderRidNil = errors.New("Sender cannot add encoding as rid is empty")
214+
errRTPSenderNoBaseEncoding = errors.New("Sender cannot add encoding as there is no base track")
215+
errRTPSenderBaseEncodingMismatch = errors.New("Sender cannot add encoding as provided track does not match base track")
216+
errRTPSenderRIDCollision = errors.New("Sender cannot encoding due to RID collision")
217+
errRTPSenderNoTrackForRID = errors.New("Sender does not have track for RID")
209218

210219
errRTPTransceiverCannotChangeMid = errors.New("errRTPSenderTrackNil")
211220
errRTPTransceiverSetSendingInvalidState = errors.New("invalid state change in RTPTransceiver.setSending")

peerconnection_media_test.go

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ func TestPeerConnection_Media_Sample(t *testing.T) {
162162
go func() {
163163
for {
164164
time.Sleep(time.Millisecond * 100)
165-
if routineErr := pcOffer.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{SenderSSRC: uint32(sender.ssrc), MediaSSRC: uint32(sender.ssrc)}}); routineErr != nil {
165+
if routineErr := pcOffer.WriteRTCP([]rtcp.Packet{&rtcp.PictureLossIndication{SenderSSRC: uint32(sender.trackEncodings[0].ssrc), MediaSSRC: uint32(sender.trackEncodings[0].ssrc)}}); routineErr != nil {
166166
awaitRTCPSenderSend <- routineErr
167167
}
168168

@@ -643,12 +643,12 @@ func TestAddTransceiverAddTrack_Reuse(t *testing.T) {
643643
track1, sender1 := addTrack()
644644
assert.Equal(t, 1, len(pc.GetTransceivers()))
645645
assert.Equal(t, sender1, tr.Sender())
646-
assert.Equal(t, track1, tr.Sender().track)
646+
assert.Equal(t, track1, tr.Sender().Track())
647647
require.NoError(t, pc.RemoveTrack(sender1))
648648

649649
track2, _ := addTrack()
650650
assert.Equal(t, 1, len(pc.GetTransceivers()))
651-
assert.Equal(t, track2, tr.Sender().track)
651+
assert.Equal(t, track2, tr.Sender().Track())
652652

653653
addTrack()
654654
assert.Equal(t, 2, len(pc.GetTransceivers()))
@@ -1256,23 +1256,47 @@ func TestPeerConnection_Simulcast(t *testing.T) {
12561256
pcOffer, pcAnswer, err := NewAPI(WithMediaEngine(m)).newPair(Configuration{})
12571257
assert.NoError(t, err)
12581258

1259-
vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2")
1259+
vp8WriterA, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2", WithRTPStreamID("a"))
12601260
assert.NoError(t, err)
12611261

1262-
_, err = pcOffer.AddTrack(vp8Writer)
1262+
sender, err := pcOffer.AddTrack(vp8WriterA)
1263+
assert.NoError(t, err)
1264+
assert.NotNil(t, sender)
1265+
1266+
vp8WriterB, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2", WithRTPStreamID("b"))
1267+
assert.NoError(t, err)
1268+
err = sender.AddEncoding(vp8WriterB)
1269+
assert.NoError(t, err)
1270+
1271+
vp8WriterC, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2", WithRTPStreamID("c"))
1272+
assert.NoError(t, err)
1273+
err = sender.AddEncoding(vp8WriterC)
12631274
assert.NoError(t, err)
12641275

12651276
ridMap = map[string]int{}
12661277
pcAnswer.OnTrack(onTrackHandler)
12671278

1268-
assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
1269-
sessionDescription = strings.Split(sessionDescription, "a=end-of-candidates\r\n")[0]
1270-
sessionDescription = filterSsrc(sessionDescription)
1271-
for _, rid := range rids {
1272-
sessionDescription += "a=" + sdpAttributeRid + ":" + rid + " send\r\n"
1279+
parameters := sender.GetParameters()
1280+
assert.Equal(t, "a", parameters.Encodings[0].RID)
1281+
assert.Equal(t, "b", parameters.Encodings[1].RID)
1282+
assert.Equal(t, "c", parameters.Encodings[2].RID)
1283+
1284+
var midID, ridID, rsidID uint8
1285+
for _, extension := range parameters.HeaderExtensions {
1286+
switch extension.URI {
1287+
case sdp.SDESMidURI:
1288+
midID = uint8(extension.ID)
1289+
case sdp.SDESRTPStreamIDURI:
1290+
ridID = uint8(extension.ID)
1291+
case sdesRepairRTPStreamIDURI:
1292+
rsidID = uint8(extension.ID)
12731293
}
1274-
return sessionDescription + "a=simulcast:send " + strings.Join(rids, ";") + "\r\n"
1275-
}))
1294+
}
1295+
assert.NotZero(t, midID)
1296+
assert.NotZero(t, ridID)
1297+
assert.NotZero(t, rsidID)
1298+
1299+
assert.NoError(t, signalPair(pcOffer, pcAnswer))
12761300

12771301
for sequenceNumber := uint16(0); !ridsFullfilled(); sequenceNumber++ {
12781302
time.Sleep(20 * time.Millisecond)
@@ -1284,17 +1308,26 @@ func TestPeerConnection_Simulcast(t *testing.T) {
12841308
SequenceNumber: sequenceNumber,
12851309
PayloadType: 96,
12861310
}
1287-
assert.NoError(t, header.SetExtension(1, []byte("0")))
1311+
assert.NoError(t, header.SetExtension(midID, []byte("0")))
12881312

12891313
// Send RSID for first 10 packets
12901314
if sequenceNumber >= 10 {
1291-
assert.NoError(t, header.SetExtension(2, []byte(rid)))
1315+
assert.NoError(t, header.SetExtension(ridID, []byte(rid)))
12921316
} else {
1293-
assert.NoError(t, header.SetExtension(3, []byte(rid)))
1317+
assert.NoError(t, header.SetExtension(rsidID, []byte(rid)))
12941318
header.SSRC += 10
12951319
}
12961320

1297-
_, err := vp8Writer.bindings[0].writeStream.WriteRTP(header, []byte{0x00})
1321+
var writer *TrackLocalStaticRTP
1322+
switch rid {
1323+
case "a":
1324+
writer = vp8WriterA
1325+
case "b":
1326+
writer = vp8WriterB
1327+
case "c":
1328+
writer = vp8WriterC
1329+
}
1330+
_, err = writer.bindings[0].writeStream.WriteRTP(header, []byte{0x00})
12981331
assert.NoError(t, err)
12991332
}
13001333
}

peerconnection_renegotiation_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -371,7 +371,7 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
371371
// Must have 3 media descriptions (2 video channels)
372372
assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
373373

374-
assert.True(t, sdpMidHasSsrc(offer, "0", sender1.ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "0", sender1.ssrc, offer.SDP)
374+
assert.True(t, sdpMidHasSsrc(offer, "0", sender1.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "0", sender1.trackEncodings[0].ssrc, offer.SDP)
375375

376376
// Remove first track, must keep same number of media
377377
// descriptions and same track ssrc for mid 1 as previous
@@ -382,7 +382,7 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
382382

383383
assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
384384

385-
assert.True(t, sdpMidHasSsrc(offer, "1", sender2.ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "1", sender2.ssrc, offer.SDP)
385+
assert.True(t, sdpMidHasSsrc(offer, "1", sender2.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.SDP: %s", "1", sender2.trackEncodings[0].ssrc, offer.SDP)
386386

387387
_, err = pcAnswer.CreateAnswer(nil)
388388
assert.Equal(t, err, &rtcerr.InvalidStateError{Err: ErrIncorrectSignalingState})
@@ -402,8 +402,8 @@ func TestPeerConnection_Transceiver_Mid(t *testing.T) {
402402
// We reuse the existing non-sending transceiver
403403
assert.Equal(t, len(offer.parsed.MediaDescriptions), 2)
404404

405-
assert.True(t, sdpMidHasSsrc(offer, "0", sender3.ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "0", sender3.ssrc, offer.SDP)
406-
assert.True(t, sdpMidHasSsrc(offer, "1", sender2.ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "1", sender2.ssrc, offer.SDP)
405+
assert.True(t, sdpMidHasSsrc(offer, "0", sender3.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "0", sender3.trackEncodings[0].ssrc, offer.SDP)
406+
assert.True(t, sdpMidHasSsrc(offer, "1", sender2.trackEncodings[0].ssrc), "Expected mid %q with ssrc %d, offer.sdp: %s", "1", sender2.trackEncodings[0].ssrc, offer.SDP)
407407

408408
closePairNow(t, pcOffer, pcAnswer)
409409
}

0 commit comments

Comments
 (0)