Skip to content

Commit

Permalink
Generate answer to match group bundle in offer
Browse files Browse the repository at this point in the history
Generate answer to match group bundle in offer
  • Loading branch information
cnderrauber committed Sep 7, 2023
1 parent ea23dec commit 7c11368
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 12 deletions.
9 changes: 7 additions & 2 deletions peerconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -2353,7 +2353,7 @@ func (pc *PeerConnection) generateUnmatchedSDP(transceivers []*RTPTransceiver, u
return nil, err
}

return populateSDP(d, isPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, true, pc.api.mediaEngine, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), candidates, iceParams, mediaSections, pc.ICEGatheringState())
return populateSDP(d, isPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, true, pc.api.mediaEngine, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), candidates, iceParams, mediaSections, pc.ICEGatheringState(), nil)
}

// generateMatchedSDP generates a SDP and takes the remote state into account
Expand Down Expand Up @@ -2451,6 +2451,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
}
}

var bundleGroup *string
// If we are offering also include unmatched local transceivers
if includeUnmatched {
if !detectedPlanB {
Expand All @@ -2469,6 +2470,10 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
mediaSections = append(mediaSections, mediaSection{id: strconv.Itoa(len(mediaSections)), data: true})
}
}
} else if remoteDescription != nil {
groupValue, _ := remoteDescription.parsed.Attribute(sdp.AttrKeyGroup)
groupValue = strings.TrimLeft(groupValue, "BUNDLE")
bundleGroup = &groupValue
}

if pc.configuration.SDPSemantics == SDPSemanticsUnifiedPlanWithFallback && detectedPlanB {
Expand All @@ -2480,7 +2485,7 @@ func (pc *PeerConnection) generateMatchedSDP(transceivers []*RTPTransceiver, use
return nil, err
}

return populateSDP(d, detectedPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, isExtmapAllowMixed, pc.api.mediaEngine, connectionRole, candidates, iceParams, mediaSections, pc.ICEGatheringState())
return populateSDP(d, detectedPlanB, dtlsFingerprints, pc.api.settingEngine.sdpMediaLevelFingerprints, pc.api.settingEngine.candidates.ICELite, isExtmapAllowMixed, pc.api.mediaEngine, connectionRole, candidates, iceParams, mediaSections, pc.ICEGatheringState(), bundleGroup)
}

func (pc *PeerConnection) setGatherCompleteHandler(handler func()) {
Expand Down
29 changes: 26 additions & 3 deletions sdp.go
Original file line number Diff line number Diff line change
Expand Up @@ -508,7 +508,7 @@ type mediaSection struct {
}

// populateSDP serializes a PeerConnections state into an SDP
func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTLSFingerprint, mediaDescriptionFingerprint bool, isICELite bool, isExtmapAllowMixed bool, mediaEngine *MediaEngine, connectionRole sdp.ConnectionRole, candidates []ICECandidate, iceParams ICEParameters, mediaSections []mediaSection, iceGatheringState ICEGatheringState) (*sdp.SessionDescription, error) {
func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTLSFingerprint, mediaDescriptionFingerprint bool, isICELite bool, isExtmapAllowMixed bool, mediaEngine *MediaEngine, connectionRole sdp.ConnectionRole, candidates []ICECandidate, iceParams ICEParameters, mediaSections []mediaSection, iceGatheringState ICEGatheringState, matchBundleGroup *string) (*sdp.SessionDescription, error) {

Check failure on line 511 in sdp.go

View workflow job for this annotation

GitHub Actions / lint / Go

cognitive complexity 37 of func `populateSDP` is high (> 30) (gocognit)
var err error
mediaDtlsFingerprints := []DTLSFingerprint{}

Expand All @@ -518,6 +518,22 @@ func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTL

bundleValue := "BUNDLE"
bundleCount := 0

bundleMatch := func(midValue string) bool {
return true
}
if matchBundleGroup != nil {
bundleTags := strings.Split(*matchBundleGroup, " ")
bundleMatch = func(midValue string) bool {
for _, tag := range bundleTags {
if tag == midValue {
return true
}
}
return false
}
}

appendBundle := func(midValue string) {
bundleValue += " " + midValue
bundleCount++
Expand All @@ -544,7 +560,11 @@ func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTL
}

if shouldAddID {
appendBundle(m.id)
if bundleMatch(m.id) {
appendBundle(m.id)
} else {
d.MediaDescriptions[len(d.MediaDescriptions)-1].MediaName.Port = sdp.RangedPort{Value: 0}
}
}
}

Expand All @@ -563,7 +583,10 @@ func populateSDP(d *sdp.SessionDescription, isPlanB bool, dtlsFingerprints []DTL
d = d.WithPropertyAttribute(sdp.AttrKeyExtMapAllowMixed)
}

return d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue), nil
if bundleCount > 0 {
d = d.WithValueAttribute(sdp.AttrKeyGroup, bundleValue)
}
return d, nil
}

func getMidValue(media *sdp.MediaDescription) string {
Expand Down
85 changes: 78 additions & 7 deletions sdp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ func TestMediaDescriptionFingerprints(t *testing.T) {
s, err = populateSDP(s, false,
dtlsFingerprints,
SDPMediaDescriptionFingerprints,
false, true, engine, sdp.ConnectionRoleActive, []ICECandidate{}, ICEParameters{}, media, ICEGatheringStateNew)
false, true, engine, sdp.ConnectionRoleActive, []ICECandidate{}, ICEParameters{}, media, ICEGatheringStateNew, nil)
assert.NoError(t, err)

sdparray, err := s.Marshal()
Expand Down Expand Up @@ -388,7 +388,7 @@ func TestPopulateSDP(t *testing.T) {

d := &sdp.SessionDescription{}

offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete)
offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

// Test contains rid map keys
Expand Down Expand Up @@ -431,7 +431,7 @@ func TestPopulateSDP(t *testing.T) {

d := &sdp.SessionDescription{}

offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete)
offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

// Test codecs
Expand All @@ -456,7 +456,7 @@ func TestPopulateSDP(t *testing.T) {
se := SettingEngine{}
se.SetLite(true)

offerSdp, err := populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete)
offerSdp, err := populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

var found bool
Expand Down Expand Up @@ -489,7 +489,7 @@ func TestPopulateSDP(t *testing.T) {

d := &sdp.SessionDescription{}

offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete)
offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, nil)
assert.NoError(t, err)

// Test codecs
Expand All @@ -507,7 +507,7 @@ func TestPopulateSDP(t *testing.T) {
})
t.Run("allow mixed extmap", func(t *testing.T) {
se := SettingEngine{}
offerSdp, err := populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete)
offerSdp, err := populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

var found bool
Expand All @@ -522,7 +522,7 @@ func TestPopulateSDP(t *testing.T) {
}
assert.Equal(t, true, found, "AllowMixedExtMap key should be present")

offerSdp, err = populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, false, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete)
offerSdp, err = populateSDP(&sdp.SessionDescription{}, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, false, &MediaEngine{}, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, []mediaSection{}, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

found = false
Expand All @@ -537,6 +537,77 @@ func TestPopulateSDP(t *testing.T) {
}
assert.Equal(t, false, found, "AllowMixedExtMap key should not be present")
})
t.Run("bundle all", func(t *testing.T) {
se := SettingEngine{}

me := &MediaEngine{}
assert.NoError(t, me.RegisterDefaultCodecs())
api := NewAPI(WithMediaEngine(me))

tr := &RTPTransceiver{kind: RTPCodecTypeVideo, api: api, codecs: me.videoCodecs}
tr.setDirection(RTPTransceiverDirectionRecvonly)
mediaSections := []mediaSection{{id: "video", transceivers: []*RTPTransceiver{tr}}}

d := &sdp.SessionDescription{}

offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, nil)
assert.Nil(t, err)

bundle, ok := offerSdp.Attribute(sdp.AttrKeyGroup)
assert.True(t, ok)
assert.Equal(t, "BUNDLE video", bundle)
})
t.Run("bundle matched", func(t *testing.T) {
se := SettingEngine{}

me := &MediaEngine{}
assert.NoError(t, me.RegisterDefaultCodecs())
api := NewAPI(WithMediaEngine(me))

tra := &RTPTransceiver{kind: RTPCodecTypeVideo, api: api, codecs: me.videoCodecs}
tra.setDirection(RTPTransceiverDirectionRecvonly)
mediaSections := []mediaSection{{id: "video", transceivers: []*RTPTransceiver{tra}}}

trv := &RTPTransceiver{kind: RTPCodecTypeAudio, api: api, codecs: me.audioCodecs}
trv.setDirection(RTPTransceiverDirectionRecvonly)
mediaSections = append(mediaSections, mediaSection{id: "audio", transceivers: []*RTPTransceiver{trv}})

d := &sdp.SessionDescription{}

matchedBundle := "audio"
offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, &matchedBundle)
assert.Nil(t, err)

bundle, ok := offerSdp.Attribute(sdp.AttrKeyGroup)
assert.True(t, ok)
assert.Equal(t, "BUNDLE audio", bundle)

mediaVideo := offerSdp.MediaDescriptions[0]
mid, ok := mediaVideo.Attribute(sdp.AttrKeyMID)
assert.True(t, ok)
assert.Equal(t, "video", mid)
assert.True(t, mediaVideo.MediaName.Port.Value == 0)
})
t.Run("empty bundle group", func(t *testing.T) {
se := SettingEngine{}

me := &MediaEngine{}
assert.NoError(t, me.RegisterDefaultCodecs())
api := NewAPI(WithMediaEngine(me))

tra := &RTPTransceiver{kind: RTPCodecTypeVideo, api: api, codecs: me.videoCodecs}
tra.setDirection(RTPTransceiverDirectionRecvonly)
mediaSections := []mediaSection{{id: "video", transceivers: []*RTPTransceiver{tra}}}

d := &sdp.SessionDescription{}

matchedBundle := ""
offerSdp, err := populateSDP(d, false, []DTLSFingerprint{}, se.sdpMediaLevelFingerprints, se.candidates.ICELite, true, me, connectionRoleFromDtlsRole(defaultDtlsRoleOffer), []ICECandidate{}, ICEParameters{}, mediaSections, ICEGatheringStateComplete, &matchedBundle)
assert.Nil(t, err)

_, ok := offerSdp.Attribute(sdp.AttrKeyGroup)
assert.False(t, ok)
})
}

func TestGetRIDs(t *testing.T) {
Expand Down

0 comments on commit 7c11368

Please sign in to comment.