Skip to content

Commit

Permalink
Set prefer codec created by remote sdp
Browse files Browse the repository at this point in the history
If a transceiver is created by remote sdp, then set
prefer codec same as offer peer.
For pion's codec match, it will use exact match
first, and then partial match. If patial match
only, the partial match codecs will become
negotiated codes. So it will be set prefer codec
when only exist partial match. And has same payload.

Add test cast for this.

refer to https://www.w3.org/TR/webrtc/#bib-rfc8829
  • Loading branch information
cnderrauber committed Nov 12, 2021
1 parent 5f6baf7 commit 635bfd9
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 0 deletions.
14 changes: 14 additions & 0 deletions peerconnection.go
Original file line number Diff line number Diff line change
Expand Up @@ -1064,6 +1064,20 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
pc.mu.Lock()
pc.addRTPTransceiver(t)
pc.mu.Unlock()

// if transceiver is create by remote sdp, set prefer codec same as remote peer
if codecs, err := codecsFromMediaDescription(media); err == nil {
filteredCodecs := []RTPCodecParameters{}
for _, codec := range codecs {
if c, matchType := codecParametersFuzzySearch(codec, pc.api.mediaEngine.getCodecsByKind(kind)); matchType == codecMatchExact {
// if codec match exact, use payloadtype register to mediaengine
codec.PayloadType = c.PayloadType
filteredCodecs = append(filteredCodecs, codec)
}
}
_ = t.SetCodecPreferences(filteredCodecs)
}

case direction == RTPTransceiverDirectionRecvonly:
if t.Direction() == RTPTransceiverDirectionSendrecv {
t.setDirection(RTPTransceiverDirectionSendonly)
Expand Down
121 changes: 121 additions & 0 deletions peerconnection_go_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1433,3 +1433,124 @@ func TestPeerConnectionNilCallback(t *testing.T) {

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

func TestTransceiverCreatedByRemoteSdpHasSameCodecOrderAsRemote(t *testing.T) {
t.Run("Codec MatchExact", func(t *testing.T) { //nolint:dupl
const remoteSdp = `v=0
o=- 4596489990601351948 2 IN IP4 127.0.0.1
s=-
t=0 0
m=video 60323 UDP/TLS/RTP/SAVPF 98 94 106
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=mid:0
a=rtpmap:98 H264/90000
a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:94 VP8/90000
a=rtpmap:106 H264/90000
a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=sendonly
m=video 60323 UDP/TLS/RTP/SAVPF 108 98 125
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=mid:1
a=rtpmap:98 H264/90000
a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:108 VP8/90000
a=sendonly
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
`
m := MediaEngine{}
assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
RTPCodecCapability: RTPCodecCapability{MimeTypeVP8, 90000, 0, "", nil},
PayloadType: 94,
}, RTPCodecTypeVideo))
assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", nil},
PayloadType: 98,
}, RTPCodecTypeVideo))

api := NewAPI(WithMediaEngine(&m))
pc, err := api.NewPeerConnection(Configuration{})
assert.NoError(t, err)
assert.NoError(t, pc.SetRemoteDescription(SessionDescription{
Type: SDPTypeOffer,
SDP: remoteSdp,
}))
ans, _ := pc.CreateAnswer(nil)
assert.NoError(t, pc.SetLocalDescription(ans))
codecOfTr1 := pc.GetTransceivers()[0].getCodecs()[0]
codecs := pc.api.mediaEngine.getCodecsByKind(RTPCodecTypeVideo)
_, matchType := codecParametersFuzzySearch(codecOfTr1, codecs)
assert.Equal(t, codecMatchExact, matchType)
codecOfTr2 := pc.GetTransceivers()[1].getCodecs()[0]
_, matchType = codecParametersFuzzySearch(codecOfTr2, codecs)
assert.Equal(t, codecMatchExact, matchType)
assert.EqualValues(t, 94, codecOfTr2.PayloadType)
assert.NoError(t, pc.Close())
})

t.Run("Codec PartialExact Only", func(t *testing.T) { //nolint:dupl
const remoteSdp = `v=0
o=- 4596489990601351948 2 IN IP4 127.0.0.1
s=-
t=0 0
m=video 60323 UDP/TLS/RTP/SAVPF 98 106
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=mid:0
a=rtpmap:98 H264/90000
a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:106 H264/90000
a=fmtp:106 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=sendonly
m=video 60323 UDP/TLS/RTP/SAVPF 125 98
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=mid:1
a=rtpmap:125 H264/90000
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=640032
a=rtpmap:98 H264/90000
a=fmtp:98 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=sendonly
`
m := MediaEngine{}
assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
RTPCodecCapability: RTPCodecCapability{MimeTypeVP8, 90000, 0, "", nil},
PayloadType: 94,
}, RTPCodecTypeVideo))
assert.NoError(t, m.RegisterCodec(RTPCodecParameters{
RTPCodecCapability: RTPCodecCapability{MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", nil},
PayloadType: 98,
}, RTPCodecTypeVideo))

api := NewAPI(WithMediaEngine(&m))
pc, err := api.NewPeerConnection(Configuration{})
assert.NoError(t, err)
assert.NoError(t, pc.SetRemoteDescription(SessionDescription{
Type: SDPTypeOffer,
SDP: remoteSdp,
}))
ans, _ := pc.CreateAnswer(nil)
assert.NoError(t, pc.SetLocalDescription(ans))
codecOfTr1 := pc.GetTransceivers()[0].getCodecs()[0]
codecs := pc.api.mediaEngine.getCodecsByKind(RTPCodecTypeVideo)
_, matchType := codecParametersFuzzySearch(codecOfTr1, codecs)
assert.Equal(t, codecMatchExact, matchType)
codecOfTr2 := pc.GetTransceivers()[1].getCodecs()[0]
_, matchType = codecParametersFuzzySearch(codecOfTr2, codecs)
assert.Equal(t, codecMatchExact, matchType)
// h.264/profile-id=640032 should be remap to 106 as same as transceiver 1
assert.EqualValues(t, 106, codecOfTr2.PayloadType)
assert.NoError(t, pc.Close())
})
}
3 changes: 3 additions & 0 deletions peerconnection_media_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ func TestPeerConnection_Media_Sample(t *testing.T) {
go func() {
for {
time.Sleep(time.Millisecond * 100)
if pcOffer.ICEConnectionState() != ICEConnectionStateConnected {
continue
}
if routineErr := vp8Track.WriteSample(media.Sample{Data: []byte{0x00}, Duration: time.Second}); routineErr != nil {
fmt.Println(routineErr)
}
Expand Down

0 comments on commit 635bfd9

Please sign in to comment.