mirror of
https://github.com/pion/webrtc.git
synced 2025-10-13 10:53:54 +08:00
Remove RTX codec if no primary
While adding transceivers from SetRemoteDescription, the filtered codecs could filter out the primart codec and leave the RTX codec in. Generating an answer with that fails `SetRemoteDescription` on remote peer due to an unrecognisable codec. Fix it by filtering out RTX is primary is not there.
This commit is contained in:

committed by
Raja Subramanian

parent
8efd17e592
commit
c82d96cb75
33
rtpcodec.go
33
rtpcodec.go
@@ -5,6 +5,7 @@ package webrtc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/pion/webrtc/v4/internal/fmtp"
|
"github.com/pion/webrtc/v4/internal/fmtp"
|
||||||
@@ -155,6 +156,38 @@ func findRTXPayloadType(needle PayloadType, haystack []RTPCodecParameters) Paylo
|
|||||||
return PayloadType(0)
|
return PayloadType(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Given needle CodecParameters, returns if needle is RTX and
|
||||||
|
// if primary codec corresponding to that needle is in the haystack of codecs.
|
||||||
|
func primaryPayloadTypeForRTXExists(needle RTPCodecParameters, haystack []RTPCodecParameters) (
|
||||||
|
isRTX bool, primaryExists bool,
|
||||||
|
) {
|
||||||
|
if !strings.EqualFold(needle.MimeType, MimeTypeRTX) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
isRTX = true
|
||||||
|
parsed := fmtp.Parse(needle.MimeType, needle.ClockRate, needle.Channels, needle.SDPFmtpLine)
|
||||||
|
aptPayload, ok := parsed.Parameter("apt")
|
||||||
|
if !ok {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
primaryPayloadType, err := strconv.Atoi(aptPayload)
|
||||||
|
if err != nil || primaryPayloadType < 0 || primaryPayloadType > 255 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c := range haystack {
|
||||||
|
if c.PayloadType == PayloadType(primaryPayloadType) {
|
||||||
|
primaryExists = true
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// For now, only FlexFEC is supported.
|
// For now, only FlexFEC is supported.
|
||||||
func findFECPayloadType(haystack []RTPCodecParameters) PayloadType {
|
func findFECPayloadType(haystack []RTPCodecParameters) PayloadType {
|
||||||
for _, c := range haystack {
|
for _, c := range haystack {
|
||||||
|
193
rtpcodec_test.go
193
rtpcodec_test.go
@@ -9,6 +9,199 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestFindPrimaryPayloadTypeForRTX(t *testing.T) {
|
||||||
|
for _, test := range []struct {
|
||||||
|
Name string
|
||||||
|
Needle RTPCodecParameters
|
||||||
|
Haystack []RTPCodecParameters
|
||||||
|
ResultIsRTX bool
|
||||||
|
ResultPrimaryExists bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
Name: "not RTX",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: false,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "incorrect fmtp",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "incorrect-fmtp",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "incomplete fmtp",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "primary payload type outside range (negative)",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "primary payload type outside range (high positive)",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=1000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "non-matching needle",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=23",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "matching needle",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "matching fmtp is a substring",
|
||||||
|
Needle: RTPCodecParameters{
|
||||||
|
PayloadType: 2,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeRTX,
|
||||||
|
ClockRate: 90000,
|
||||||
|
SDPFmtpLine: "apt=1;rtx-time:2000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Haystack: []RTPCodecParameters{
|
||||||
|
{
|
||||||
|
PayloadType: 1,
|
||||||
|
RTPCodecCapability: RTPCodecCapability{
|
||||||
|
MimeType: MimeTypeH264,
|
||||||
|
ClockRate: 90000,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ResultIsRTX: true,
|
||||||
|
ResultPrimaryExists: true,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(test.Name, func(t *testing.T) {
|
||||||
|
isRTX, primaryExists := primaryPayloadTypeForRTXExists(test.Needle, test.Haystack)
|
||||||
|
assert.Equal(t, test.ResultIsRTX, isRTX)
|
||||||
|
assert.Equal(t, test.ResultPrimaryExists, primaryExists)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestFindFECPayloadType(t *testing.T) {
|
func TestFindFECPayloadType(t *testing.T) {
|
||||||
for _, test := range []struct {
|
for _, test := range []struct {
|
||||||
Haystack []RTPCodecParameters
|
Haystack []RTPCodecParameters
|
||||||
|
@@ -8,6 +8,7 @@ package webrtc
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
|
|
||||||
@@ -60,6 +61,19 @@ func (t *RTPTransceiver) SetCodecPreferences(codecs []RTPCodecParameters) error
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove RTX codecs if there is no corresponding primary codec
|
||||||
|
for i := len(codecs) - 1; i >= 0; i-- {
|
||||||
|
c := codecs[i]
|
||||||
|
if !strings.EqualFold(c.MimeType, MimeTypeRTX) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if isRTX, primaryExists := primaryPayloadTypeForRTXExists(c, codecs); isRTX && !primaryExists {
|
||||||
|
// no primary for RTX, remove the RTX
|
||||||
|
codecs = append(codecs[:i], codecs[i+1:]...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
t.codecs = codecs
|
t.codecs = codecs
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
Reference in New Issue
Block a user