@@ -23,13 +23,14 @@ import (
23
23
// trackDetails represents any media source that can be represented in a SDP
24
24
// This isn't keyed by SSRC because it also needs to support rid based sources.
25
25
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
33
34
}
34
35
35
36
func trackDetailsForSSRC (trackDetails []trackDetails , ssrc SSRC ) * trackDetails {
@@ -91,6 +92,7 @@ func trackDetailsFromSDP(
91
92
for _ , media := range s .MediaDescriptions {
92
93
tracksInMediaSection := []trackDetails {}
93
94
rtxRepairFlows := map [uint64 ]uint64 {}
95
+ fecRepairFlows := map [uint64 ]uint64 {}
94
96
95
97
// Plan B can have multiple tracks in a single media section
96
98
streamID := ""
@@ -143,7 +145,35 @@ func trackDetailsFromSDP(
143
145
for i := range tracksInMediaSection {
144
146
if tracksInMediaSection [i ].ssrcs [0 ] == SSRC (baseSsrc ) {
145
147
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
147
177
}
148
178
}
149
179
}
@@ -171,6 +201,9 @@ func trackDetailsFromSDP(
171
201
if _ , ok := rtxRepairFlows [ssrc ]; ok {
172
202
continue // This ssrc is a RTX repair flow, ignore
173
203
}
204
+ if _ , ok := fecRepairFlows [ssrc ]; ok {
205
+ continue // This ssrc is a FEC repair flow, ignore
206
+ }
174
207
175
208
if len (split ) == 3 && strings .HasPrefix (split [1 ], "msid:" ) {
176
209
streamID = split [1 ][len ("msid:" ):]
@@ -197,7 +230,13 @@ func trackDetailsFromSDP(
197
230
for r , baseSsrc := range rtxRepairFlows {
198
231
if baseSsrc == ssrc {
199
232
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
201
240
}
202
241
}
203
242
@@ -243,8 +282,12 @@ func trackDetailsToRTPReceiveParameters(trackDetails *trackDetails) RTPReceivePa
243
282
encodings [i ].SSRC = trackDetails .ssrcs [i ]
244
283
}
245
284
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
248
291
}
249
292
}
250
293
@@ -430,10 +473,26 @@ func addSenderSDP(
430
473
sendParameters := sender .GetParameters ()
431
474
for _ , encoding := range sendParameters .Encodings {
432
475
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
+ )
434
485
}
435
486
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
+ )
437
496
}
438
497
439
498
media = media .WithMediaSource (
0 commit comments