diff --git a/util.go b/util.go index f78824b..0f14f15 100644 --- a/util.go +++ b/util.go @@ -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 @@ -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: [] 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) { @@ -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() @@ -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 } diff --git a/util_test.go b/util_test.go index c910a7b..d1348d1 100644 --- a/util_test.go +++ b/util_test.go @@ -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", ""), }, }, }, @@ -103,10 +105,11 @@ 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"}, }, }, { @@ -114,10 +117,11 @@ func TestGetCodecForPayloadType(t *testing.T) { 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"}, }, }, { @@ -125,10 +129,11 @@ func TestGetCodecForPayloadType(t *testing.T) { 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"}, }, }, { @@ -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"}, }, }, {