Skip to content

Commit ef285fb

Browse files
boks1971Sean-Der
authored andcommitted
Use RIDs for SSRC resolution
Problem: -------- Firefox (testing with Firefox 93) sends an `offer` with simulcast track which includes both RIDs and SSRCs. When track details are gathered, RIDs are fetched using `getRids` which returns a map. A `range` is done on the returned map and RIDs are appended to the `rids` array in `trackDetails`. And then SSRCs are read from SDP and set into the `ssrcs` array of `trackDetails`. As map range order is not guaranteed, some times the RID index and SSRC index in their respective arrays do not match. Due to the mismatch, services like ion-sfu which rely on RID to find the correct spatial layer get confused and end up forwarding the wrong layer. Solution(s): ------------ There are three possible solutions I could think of 1. The simplest is to not populate SSRCs in `trackDetails` if RIDs are available. Let `handleIncomingSSRC` do the SSRC resolution based on RID. According to RFC 8853 (https://www.ietf.org/rfc/rfc8853.pdf), the binding to SSRC should happen using RID. This is the change I have made in this PR. See testing below for browsers tested. 2. Look for `simulcast` attribute in SDP and take the RID ordering from that line in `getRids` if that attribute is available. If not fall back to `rid` attribute. Also, change `getRids` to return an array. But, I cannot find an RFC which defines behaviour when both RID and SSRC are used in `offer`. The question is, "Will the `ssrc` attribute ordering match the `rid` ordering?". If that is not guaranteed, this will run into trouble. This should be easy to do though if we want to go down this route. 3. The hardest option is to change the receiver SSRC based on RID. But, that makes it too complicated (for example if we have to change SSRC binding of a receiver based on received RID, there will be two receivers with the same SSRC binding unless there is some way to swap bindings of receivers) Testing: -------- Tested on Firefox, Firefox 78.15.0esr, Chrome, Ssafari and ensured that Simulcast sender and receiver are in sync for rid/ssrc/spatial layer resolution.
1 parent 0180ee3 commit ef285fb

File tree

2 files changed

+0
-59
lines changed

2 files changed

+0
-59
lines changed

peerconnection_media_test.go

-54
Original file line numberDiff line numberDiff line change
@@ -1195,58 +1195,4 @@ func TestPeerConnection_Simulcast(t *testing.T) {
11951195
assertRidCorrect(t)
11961196
closePairNow(t, pcOffer, pcAnswer)
11971197
})
1198-
1199-
t.Run("SSRC Based", func(t *testing.T) {
1200-
pcOffer, pcAnswer, err := NewAPI(WithMediaEngine(m)).newPair(Configuration{})
1201-
assert.NoError(t, err)
1202-
1203-
vp8Writer, err := NewTrackLocalStaticRTP(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion2")
1204-
assert.NoError(t, err)
1205-
1206-
_, err = pcOffer.AddTrack(vp8Writer)
1207-
assert.NoError(t, err)
1208-
1209-
ridMap = map[string]int{}
1210-
pcAnswer.OnTrack(onTrackHandler)
1211-
1212-
assert.NoError(t, signalPairWithModification(pcOffer, pcAnswer, func(sessionDescription string) string {
1213-
sessionDescription = strings.Split(sessionDescription, "a=end-of-candidates\r\n")[0]
1214-
sessionDescription = filterSsrc(sessionDescription)
1215-
1216-
for _, rid := range rids {
1217-
sessionDescription += "a=" + sdpAttributeRid + ":" + rid + " send\r\n"
1218-
}
1219-
sessionDescription += "a=simulcast:send " + strings.Join(rids, ";") + "\r\n"
1220-
1221-
return sessionDescription + `a=ssrc:5000 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1222-
a=ssrc:5001 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1223-
a=ssrc:5002 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1224-
a=ssrc:5003 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1225-
a=ssrc:5004 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1226-
a=ssrc:5005 cname:{49d59adc-fae6-407b-8850-2eb4a5e9b76e}
1227-
a=ssrc-group:FID 5000 5001
1228-
a=ssrc-group:FID 5002 5003
1229-
a=ssrc-group:FID 5004 5005
1230-
`
1231-
}))
1232-
1233-
for sequenceNumber := uint16(0); !ridsFullfilled(); sequenceNumber++ {
1234-
time.Sleep(20 * time.Millisecond)
1235-
1236-
for ssrc := 5000; ssrc <= 5004; ssrc += 2 {
1237-
header := &rtp.Header{
1238-
Version: 2,
1239-
SSRC: uint32(ssrc),
1240-
SequenceNumber: sequenceNumber,
1241-
PayloadType: 96,
1242-
}
1243-
1244-
_, err := vp8Writer.bindings[0].writeStream.WriteRTP(header, []byte{0x00})
1245-
assert.NoError(t, err)
1246-
}
1247-
}
1248-
1249-
assertRidCorrect(t)
1250-
closePairNow(t, pcOffer, pcAnswer)
1251-
})
12521198
}

sdp.go

-5
Original file line numberDiff line numberDiff line change
@@ -189,11 +189,6 @@ func trackDetailsFromSDP(log logging.LeveledLogger, s *sdp.SessionDescription) (
189189
for rid := range rids {
190190
simulcastTrack.rids = append(simulcastTrack.rids, rid)
191191
}
192-
if len(simulcastTrack.rids) == len(tracksInMediaSection) {
193-
for i := range tracksInMediaSection {
194-
simulcastTrack.ssrcs = append(simulcastTrack.ssrcs, tracksInMediaSection[i].ssrcs...)
195-
}
196-
}
197192

198193
tracksInMediaSection = []trackDetails{simulcastTrack}
199194
}

0 commit comments

Comments
 (0)