Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backport #2972 to v3 #2973

Merged
merged 1 commit into from
Dec 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions mediaengine.go
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@
}

// Look up a codec and enable if it exists
func (m *MediaEngine) matchRemoteCodec(remoteCodec RTPCodecParameters, typ RTPCodecType, exactMatches, partialMatches []RTPCodecParameters) (codecMatchType, error) {
func (m *MediaEngine) matchRemoteCodec(remoteCodec RTPCodecParameters, typ RTPCodecType, exactMatches, partialMatches []RTPCodecParameters) (RTPCodecParameters, codecMatchType, error) {
codecs := m.videoCodecs
if typ == RTPCodecTypeAudio {
codecs = m.audioCodecs
Expand All @@ -411,7 +411,7 @@
if apt, hasApt := remoteFmtp.Parameter("apt"); hasApt {
payloadType, err := strconv.ParseUint(apt, 10, 8)
if err != nil {
return codecMatchNone, err
return RTPCodecParameters{}, codecMatchNone, err

Check warning on line 414 in mediaengine.go

View check run for this annotation

Codecov / codecov/patch

mediaengine.go#L414

Added line #L414 was not covered by tests
}

aptMatch := codecMatchNone
Expand All @@ -435,7 +435,7 @@
}

if aptMatch == codecMatchNone {
return codecMatchNone, nil // not an error, we just ignore this codec we don't support
return RTPCodecParameters{}, codecMatchNone, nil // not an error, we just ignore this codec we don't support
}

// replace the apt value with the original codec's payload type
Expand All @@ -445,15 +445,15 @@
}

// if apt's media codec is partial match, then apt codec must be partial match too
_, matchType := codecParametersFuzzySearch(toMatchCodec, codecs)
localCodec, matchType := codecParametersFuzzySearch(toMatchCodec, codecs)
if matchType == codecMatchExact && aptMatch == codecMatchPartial {
matchType = codecMatchPartial
}
return matchType, nil
return localCodec, matchType, nil
}

_, matchType := codecParametersFuzzySearch(remoteCodec, codecs)
return matchType, nil
localCodec, matchType := codecParametersFuzzySearch(remoteCodec, codecs)
return localCodec, matchType, nil
}

// Update header extensions from a remote media section
Expand Down Expand Up @@ -555,16 +555,18 @@
exactMatches := make([]RTPCodecParameters, 0, len(codecs))
partialMatches := make([]RTPCodecParameters, 0, len(codecs))

for _, codec := range codecs {
matchType, mErr := m.matchRemoteCodec(codec, typ, exactMatches, partialMatches)
for _, remoteCodec := range codecs {
localCodec, matchType, mErr := m.matchRemoteCodec(remoteCodec, typ, exactMatches, partialMatches)
if mErr != nil {
return mErr
}

remoteCodec.RTCPFeedback = rtcpFeedbackIntersection(localCodec.RTCPFeedback, remoteCodec.RTCPFeedback)

if matchType == codecMatchExact {
exactMatches = append(exactMatches, codec)
exactMatches = append(exactMatches, remoteCodec)
} else if matchType == codecMatchPartial {
partialMatches = append(partialMatches, codec)
partialMatches = append(partialMatches, remoteCodec)
}
}

Expand Down
71 changes: 71 additions & 0 deletions mediaengine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -722,3 +722,74 @@ a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001
})
}
}

// rtcp-fb should be an intersection of local and remote
func TestRTCPFeedbackHandling(t *testing.T) {
const offerSdp = `
v=0
o=- 8448668841136641781 4 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS 4beea6b0-cf95-449c-a1ec-78e16b247426
m=video 9 UDP/TLS/RTP/SAVPF 96
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:1/MvHwjAyVf27aLu
a=ice-pwd:3dBU7cFOBl120v33cynDvN1E
a=ice-options:google-ice
a=fingerprint:sha-256 75:74:5A:A6:A4:E5:52:F4:A7:67:4C:01:C7:EE:91:3F:21:3D:A2:E3:53:7B:6F:30:86:F2:30:AA:65:FB:04:24
a=setup:actpass
a=mid:0
a=sendrecv
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 nack
`

runTest := func(createTransceiver bool, t *testing.T) {
m := &MediaEngine{}
assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
RTPCodecCapability: RTPCodecCapability{MimeType: MimeTypeVP8, ClockRate: 90000, RTCPFeedback: []RTCPFeedback{
{Type: TypeRTCPFBTransportCC},
{Type: TypeRTCPFBNACK},
}},
PayloadType: 96,
}, RTPCodecTypeVideo))

peerConnection, err := NewAPI(WithMediaEngine(m)).NewPeerConnection(Configuration{})
assert.NoError(t, err)

if createTransceiver {
_, err = peerConnection.AddTransceiverFromKind(RTPCodecTypeVideo)
assert.NoError(t, err)
}

assert.NoError(t, peerConnection.SetRemoteDescription(SessionDescription{
Type: SDPTypeOffer,
SDP: offerSdp,
},
))

answer, err := peerConnection.CreateAnswer(nil)
assert.NoError(t, err)

// Both clients support
assert.True(t, strings.Contains(answer.SDP, "a=rtcp-fb:96 nack"))

// Only one client supports
assert.False(t, strings.Contains(answer.SDP, "a=rtcp-fb:96 goog-remb"))
assert.False(t, strings.Contains(answer.SDP, "a=rtcp-fb:96 transport-cc"))

assert.NoError(t, peerConnection.Close())
}

t.Run("recvonly", func(t *testing.T) {
runTest(false, t)
})

t.Run("sendrecv", func(t *testing.T) {
runTest(true, t)
})
}
13 changes: 13 additions & 0 deletions rtpcodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,16 @@ func codecParametersFuzzySearch(needle RTPCodecParameters, haystack []RTPCodecPa

return RTPCodecParameters{}, codecMatchNone
}
func rtcpFeedbackIntersection(a, b []RTCPFeedback) (out []RTCPFeedback) {
for _, aFeedback := range a {
for _, bFeeback := range b {
if aFeedback.Type == bFeeback.Type && aFeedback.Parameter == bFeeback.Parameter {
out = append(out, aFeedback)
break
}
}
}

return
}

1 change: 1 addition & 0 deletions rtptransceiver.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ func (t *RTPTransceiver) getCodecs() []RTPCodecParameters {
if codec.PayloadType == 0 {
codec.PayloadType = c.PayloadType
}
codec.RTCPFeedback = rtcpFeedbackIntersection(codec.RTCPFeedback, c.RTCPFeedback)
filteredCodecs = append(filteredCodecs, codec)
}
}
Expand Down
Loading