Skip to content

Commit

Permalink
Add support for rtcp-fb:*
Browse files Browse the repository at this point in the history
According to Chrome PSA:
https://groups.google.com/g/discuss-webrtc/c/Y_h2B-NOzW0 rtcp-fb:*
might start getting sent by chrome in M112. This was rolled back but may
land again in M114 according to maintainers.

Also, according to
https://webrtc.googlesource.com/src.git/+/8155227/#F0
Chrome may plan on sending both rtcp-fb:* and rtcp-fb:<int> variants for
some time to allow migration in downstream projects.
This change correctly parses the wildcard case to add the feedback to
all payload types found in the SDP, to maintain compatibility with Pion.

Resolves #172
  • Loading branch information
thebongy authored and Sean-Der committed Mar 29, 2024
1 parent 84cf380 commit 84d5ab0
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 26 deletions.
52 changes: 39 additions & 13 deletions util.go
Expand Up @@ -86,6 +86,16 @@ func (c Codec) String() string {
return fmt.Sprintf("%d %s/%d/%s (%s) [%s]", c.PayloadType, c.Name, c.ClockRate, c.EncodingParameters, c.Fmtp, strings.Join(c.RTCPFeedback, ", "))
}

func (c *Codec) appendRTCPFeedback(rtcpFeedback string) {
for _, existingRTCPFeedback := range c.RTCPFeedback {
if existingRTCPFeedback == rtcpFeedback {
return
}
}

c.RTCPFeedback = append(c.RTCPFeedback, rtcpFeedback)
}

func parseRtpmap(rtpmap string) (Codec, error) {
var codec Codec
parsingFailed := errExtractCodecRtpmap
Expand Down Expand Up @@ -153,30 +163,33 @@ func parseFmtp(fmtp string) (Codec, error) {
return codec, nil
}

func parseRtcpFb(rtcpFb string) (Codec, error) {
var codec Codec
parsingFailed := errExtractCodecRtcpFb
func parseRtcpFb(rtcpFb string) (codec Codec, isWildcard bool, err error) {
var ptInt uint64
err = errExtractCodecRtcpFb

// a=ftcp-fb:<payload type> <RTCP feedback type> [<RTCP feedback parameter>]
split := strings.SplitN(rtcpFb, " ", 2)
if len(split) != 2 {
return codec, parsingFailed
return
}

ptSplit := strings.Split(split[0], ":")
if len(ptSplit) != 2 {
return codec, parsingFailed
return
}

ptInt, err := strconv.ParseUint(ptSplit[1], 10, 8)
if err != nil {
return codec, parsingFailed
isWildcard = ptSplit[1] == "*"
if !isWildcard {
ptInt, err = strconv.ParseUint(ptSplit[1], 10, 8)
if err != nil {
return
}

codec.PayloadType = uint8(ptInt)
}

codec.PayloadType = uint8(ptInt)
codec.RTCPFeedback = append(codec.RTCPFeedback, split[1])

return codec, nil
return codec, isWildcard, nil
}

func mergeCodecs(codec Codec, codecs map[uint8]Codec) {
Expand Down Expand Up @@ -217,6 +230,7 @@ func (s *SessionDescription) buildCodecMap() map[uint8]Codec {
},
}

wildcardRTCPFeedback := []string{}
for _, m := range s.MediaDescriptions {
for _, a := range m.Attributes {
attr := a.String()
Expand All @@ -232,14 +246,26 @@ func (s *SessionDescription) buildCodecMap() map[uint8]Codec {
mergeCodecs(codec, codecs)
}
case strings.HasPrefix(attr, "rtcp-fb:"):
codec, err := parseRtcpFb(attr)
if err == nil {
codec, isWildcard, err := parseRtcpFb(attr)
switch {
case err != nil:
case isWildcard:
wildcardRTCPFeedback = append(wildcardRTCPFeedback, codec.RTCPFeedback...)
default:
mergeCodecs(codec, codecs)
}
}
}
}

for i, codec := range codecs {
for _, newRTCPFeedback := range wildcardRTCPFeedback {
codec.appendRTCPFeedback(newRTCPFeedback)
}

codecs[i] = codec
}

return codecs
}

Expand Down
31 changes: 18 additions & 13 deletions util_test.go
Expand Up @@ -33,6 +33,8 @@ func getTestSessionDescription() SessionDescription {
NewAttribute("rtcp-fb:97 ccm fir", ""),
NewAttribute("rtcp-fb:97 nack", ""),
NewAttribute("rtcp-fb:97 nack pli", ""),
NewAttribute("rtcp-fb:* transport-cc", ""),
NewAttribute("rtcp-fb:* nack", ""),
},
},
},
Expand Down Expand Up @@ -103,32 +105,35 @@ func TestGetCodecForPayloadType(t *testing.T) {
getTestSessionDescription(),
120,
Codec{
PayloadType: 120,
Name: "VP8",
ClockRate: 90000,
Fmtp: "max-fs=12288;max-fr=60",
PayloadType: 120,
Name: "VP8",
ClockRate: 90000,
Fmtp: "max-fs=12288;max-fr=60",
RTCPFeedback: []string{"transport-cc", "nack"},
},
},
{
"vp9",
getTestSessionDescription(),
121,
Codec{
PayloadType: 121,
Name: "VP9",
ClockRate: 90000,
Fmtp: "max-fs=12288;max-fr=60",
PayloadType: 121,
Name: "VP9",
ClockRate: 90000,
Fmtp: "max-fs=12288;max-fr=60",
RTCPFeedback: []string{"transport-cc", "nack"},
},
},
{
"h264 126",
getTestSessionDescription(),
126,
Codec{
PayloadType: 126,
Name: "H264",
ClockRate: 90000,
Fmtp: "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1",
PayloadType: 126,
Name: "H264",
ClockRate: 90000,
Fmtp: "profile-level-id=42e01f;level-asymmetry-allowed=1;packetization-mode=1",
RTCPFeedback: []string{"transport-cc", "nack"},
},
},
{
Expand All @@ -140,7 +145,7 @@ func TestGetCodecForPayloadType(t *testing.T) {
Name: "H264",
ClockRate: 90000,
Fmtp: "profile-level-id=42e01f;level-asymmetry-allowed=1",
RTCPFeedback: []string{"ccm fir", "nack", "nack pli"},
RTCPFeedback: []string{"ccm fir", "nack", "nack pli", "transport-cc"},
},
},
{
Expand Down

0 comments on commit 84d5ab0

Please sign in to comment.