Skip to content

Commit 4742d1f

Browse files
committed
Fix trackDetailsFromSDP not handling fec ssrc
1 parent e68ce42 commit 4742d1f

File tree

3 files changed

+114
-19
lines changed

3 files changed

+114
-19
lines changed

peerconnection.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1700,7 +1700,10 @@ func (pc *PeerConnection) handleIncomingSSRC(rtpStream io.Reader, ssrc SSRC) err
17001700

17011701
// If a SSRC already exists in the RemoteDescription don't perform heuristics upon it
17021702
for _, track := range trackDetailsFromSDP(pc.log, remoteDescription.parsed) {
1703-
if track.repairSsrc != nil && ssrc == *track.repairSsrc {
1703+
if track.rtxSsrc != nil && ssrc == *track.rtxSsrc {
1704+
return nil
1705+
}
1706+
if track.fecSsrc != nil && ssrc == *track.fecSsrc {
17041707
return nil
17051708
}
17061709
for _, trackSsrc := range track.ssrcs {

sdp.go

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,14 @@ import (
2323
// trackDetails represents any media source that can be represented in a SDP
2424
// This isn't keyed by SSRC because it also needs to support rid based sources.
2525
type trackDetails struct {
26-
mid string
27-
kind RTPCodecType
28-
streamID string
29-
id string
30-
ssrcs []SSRC
31-
repairSsrc *SSRC
32-
rids []string
26+
mid string
27+
kind RTPCodecType
28+
streamID string
29+
id string
30+
ssrcs []SSRC
31+
rtxSsrc *SSRC
32+
fecSsrc *SSRC
33+
rids []string
3334
}
3435

3536
func trackDetailsForSSRC(trackDetails []trackDetails, ssrc SSRC) *trackDetails {
@@ -91,6 +92,7 @@ func trackDetailsFromSDP(
9192
for _, media := range s.MediaDescriptions {
9293
tracksInMediaSection := []trackDetails{}
9394
rtxRepairFlows := map[uint64]uint64{}
95+
fecRepairFlows := map[uint64]uint64{}
9496

9597
// Plan B can have multiple tracks in a single media section
9698
streamID := ""
@@ -143,7 +145,35 @@ func trackDetailsFromSDP(
143145
for i := range tracksInMediaSection {
144146
if tracksInMediaSection[i].ssrcs[0] == SSRC(baseSsrc) {
145147
repairSsrc := SSRC(rtxRepairFlow)
146-
tracksInMediaSection[i].repairSsrc = &repairSsrc
148+
tracksInMediaSection[i].rtxSsrc = &repairSsrc
149+
}
150+
}
151+
}
152+
} else if split[0] == sdp.SemanticTokenForwardErrorCorrectionFramework {
153+
// Similar to above, lines like `a=ssrc-group:FEC-FR aaaaa bbbbb`
154+
// means for video ssrc aaaaa, there's a FEC track bbbbb
155+
if len(split) == 3 {
156+
baseSsrc, err := strconv.ParseUint(split[1], 10, 32)
157+
if err != nil {
158+
log.Warnf("Failed to parse SSRC: %v", err)
159+
160+
continue
161+
}
162+
fecRepairFlow, err := strconv.ParseUint(split[2], 10, 32)
163+
if err != nil {
164+
log.Warnf("Failed to parse SSRC: %v", err)
165+
166+
continue
167+
}
168+
fecRepairFlows[fecRepairFlow] = baseSsrc
169+
tracksInMediaSection = filterTrackWithSSRC(
170+
tracksInMediaSection,
171+
SSRC(fecRepairFlow),
172+
) // Remove if fec was added as track before
173+
for i := range tracksInMediaSection {
174+
if tracksInMediaSection[i].ssrcs[0] == SSRC(baseSsrc) {
175+
repairSsrc := SSRC(fecRepairFlow)
176+
tracksInMediaSection[i].fecSsrc = &repairSsrc
147177
}
148178
}
149179
}
@@ -171,6 +201,9 @@ func trackDetailsFromSDP(
171201
if _, ok := rtxRepairFlows[ssrc]; ok {
172202
continue // This ssrc is a RTX repair flow, ignore
173203
}
204+
if _, ok := fecRepairFlows[ssrc]; ok {
205+
continue // This ssrc is a FEC repair flow, ignore
206+
}
174207

175208
if len(split) == 3 && strings.HasPrefix(split[1], "msid:") {
176209
streamID = split[1][len("msid:"):]
@@ -197,7 +230,13 @@ func trackDetailsFromSDP(
197230
for r, baseSsrc := range rtxRepairFlows {
198231
if baseSsrc == ssrc {
199232
repairSsrc := SSRC(r) //nolint:gosec // G115
200-
trackDetails.repairSsrc = &repairSsrc
233+
trackDetails.rtxSsrc = &repairSsrc
234+
}
235+
}
236+
for r, baseSsrc := range fecRepairFlows {
237+
if baseSsrc == ssrc {
238+
fecSsrc := SSRC(r) //nolint:gosec // G115
239+
trackDetails.fecSsrc = &fecSsrc
201240
}
202241
}
203242

@@ -243,8 +282,12 @@ func trackDetailsToRTPReceiveParameters(trackDetails *trackDetails) RTPReceivePa
243282
encodings[i].SSRC = trackDetails.ssrcs[i]
244283
}
245284

246-
if trackDetails.repairSsrc != nil {
247-
encodings[i].RTX.SSRC = *trackDetails.repairSsrc
285+
if trackDetails.rtxSsrc != nil {
286+
encodings[i].RTX.SSRC = *trackDetails.rtxSsrc
287+
}
288+
289+
if trackDetails.fecSsrc != nil {
290+
encodings[i].FEC.SSRC = *trackDetails.fecSsrc
248291
}
249292
}
250293

@@ -430,10 +473,26 @@ func addSenderSDP(
430473
sendParameters := sender.GetParameters()
431474
for _, encoding := range sendParameters.Encodings {
432475
if encoding.RTX.SSRC != 0 {
433-
media = media.WithValueAttribute("ssrc-group", fmt.Sprintf("FID %d %d", encoding.SSRC, encoding.RTX.SSRC))
476+
media = media.WithValueAttribute(
477+
"ssrc-group",
478+
fmt.Sprintf(
479+
"%s %d %d",
480+
sdp.SemanticTokenFlowIdentification,
481+
encoding.SSRC,
482+
encoding.RTX.SSRC,
483+
),
484+
)
434485
}
435486
if encoding.FEC.SSRC != 0 {
436-
media = media.WithValueAttribute("ssrc-group", fmt.Sprintf("FEC-FR %d %d", encoding.SSRC, encoding.FEC.SSRC))
487+
media = media.WithValueAttribute(
488+
"ssrc-group",
489+
fmt.Sprintf(
490+
"%s %d %d",
491+
sdp.SemanticTokenForwardErrorCorrectionFramework,
492+
encoding.SSRC,
493+
encoding.FEC.SSRC,
494+
),
495+
)
437496
}
438497

439498
media = media.WithMediaSource(

sdp_test.go

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import (
1616
"github.com/pion/sdp/v3"
1717
"github.com/pion/transport/v3/test"
1818
"github.com/stretchr/testify/assert"
19+
"github.com/stretchr/testify/require"
1920
)
2021

2122
func TestExtractFingerprint(t *testing.T) {
@@ -454,6 +455,38 @@ func TestTrackDetailsFromSDP(t *testing.T) {
454455
}
455456
})
456457

458+
t.Run("Tracks unknown, video with RTX and FEC", func(t *testing.T) {
459+
descr := &sdp.SessionDescription{
460+
MediaDescriptions: []*sdp.MediaDescription{
461+
{
462+
MediaName: sdp.MediaName{
463+
Media: "video",
464+
},
465+
Attributes: []sdp.Attribute{
466+
{Key: "mid", Value: "0"},
467+
{Key: "sendrecv"},
468+
{Key: "ssrc-group", Value: "FID 3000 4000"},
469+
{Key: "ssrc-group", Value: "FEC-FR 3000 5000"},
470+
{Key: "ssrc", Value: "3000 msid:video_trk_label video_trk_guid"},
471+
{Key: "ssrc", Value: "4000 msid:rtx_trk_label rtx_trk_guid"},
472+
{Key: "ssrc", Value: "5000 msid:fec_trk_label fec_trk_guid"},
473+
},
474+
},
475+
},
476+
}
477+
478+
tracks := trackDetailsFromSDP(nil, descr)
479+
assert.Equal(t, 1, len(tracks))
480+
track := tracks[0]
481+
assert.Equal(t, RTPCodecTypeVideo, track.kind)
482+
assert.Equal(t, SSRC(3000), track.ssrcs[0])
483+
assert.Equal(t, "video_trk_label", track.streamID)
484+
require.NotNil(t, track.rtxSsrc, "missing RTX ssrc for video track")
485+
assert.Equal(t, SSRC(4000), *track.rtxSsrc)
486+
require.NotNil(t, track.fecSsrc, "missing FEC ssrc for video track")
487+
assert.Equal(t, SSRC(5000), *track.fecSsrc)
488+
})
489+
457490
t.Run("inactive and recvonly tracks ignored", func(t *testing.T) {
458491
descr := &sdp.SessionDescription{
459492
MediaDescriptions: []*sdp.MediaDescription{
@@ -512,8 +545,8 @@ func TestTrackDetailsFromSDP(t *testing.T) {
512545

513546
tracks := trackDetailsFromSDP(nil, descr)
514547
assert.Equal(t, 2, len(tracks))
515-
assert.Equal(t, SSRC(4000), *tracks[0].repairSsrc)
516-
assert.Equal(t, SSRC(6000), *tracks[1].repairSsrc)
548+
assert.Equal(t, SSRC(4000), *tracks[0].rtxSsrc)
549+
assert.Equal(t, SSRC(6000), *tracks[1].rtxSsrc)
517550
})
518551
}
519552

@@ -1235,13 +1268,13 @@ a=sendrecv
12351268
t.Run(testCase.name, func(t *testing.T) {
12361269
checkRTXSupport := func(s *sdp.SessionDescription) {
12371270
// RTX is never enabled for audio
1238-
assert.Nil(t, trackDetailsFromSDP(nil, s)[0].repairSsrc)
1271+
assert.Nil(t, trackDetailsFromSDP(nil, s)[0].rtxSsrc)
12391272

12401273
// RTX is conditionally enabled for video
12411274
if testCase.rtxExpected {
1242-
assert.NotNil(t, trackDetailsFromSDP(nil, s)[1].repairSsrc)
1275+
assert.NotNil(t, trackDetailsFromSDP(nil, s)[1].rtxSsrc)
12431276
} else {
1244-
assert.Nil(t, trackDetailsFromSDP(nil, s)[1].repairSsrc)
1277+
assert.Nil(t, trackDetailsFromSDP(nil, s)[1].rtxSsrc)
12451278
}
12461279
}
12471280

0 commit comments

Comments
 (0)