replace Format.Marshal() with RTPMap() and FMTP() (#253)

This commit is contained in:
Alessandro Ros
2023-04-15 13:46:19 +02:00
committed by GitHub
parent fee147222e
commit a955288571
43 changed files with 414 additions and 340 deletions

View File

@@ -269,7 +269,7 @@ func TestClientPlay(t *testing.T) {
forma := &formats.Generic{ forma := &formats.Generic{
PayloadTyp: 96, PayloadTyp: 96,
RTPMap: "private/90000", RTPMa: "private/90000",
} }
err = forma.Init() err = forma.Init()
require.NoError(t, err) require.NoError(t, err)
@@ -543,7 +543,7 @@ func TestClientPlayPartial(t *testing.T) {
forma := &formats.Generic{ forma := &formats.Generic{
PayloadTyp: 96, PayloadTyp: 96,
RTPMap: "private/90000", RTPMa: "private/90000",
} }
err = forma.Init() err = forma.Init()
require.NoError(t, err) require.NoError(t, err)
@@ -2932,7 +2932,7 @@ func TestClientPlayDecodeErrors(t *testing.T) {
Type: media.TypeApplication, Type: media.TypeApplication,
Formats: []formats.Format{&formats.Generic{ Formats: []formats.Format{&formats.Generic{
PayloadTyp: 97, PayloadTyp: 97,
RTPMap: "private/90000", RTPMa: "private/90000",
}}, }},
}} }}
resetMediaControls(medias) resetMediaControls(medias)

View File

@@ -16,21 +16,6 @@ type AV1 struct {
Tier *int Tier *int
} }
// String implements Format.
func (f *AV1) String() string {
return "AV1"
}
// ClockRate implements Format.
func (f *AV1) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *AV1) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *AV1) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *AV1) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -68,8 +53,28 @@ func (f *AV1) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *AV1) Marshal() (string, map[string]string) { func (f *AV1) String() string {
return "AV1"
}
// ClockRate implements Format.
func (f *AV1) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *AV1) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *AV1) RTPMap() string {
return "AV1/90000"
}
// FMTP implements Format.
func (f *AV1) FMTP() map[string]string {
fmtp := make(map[string]string) fmtp := make(map[string]string)
if f.LevelIdx != nil { if f.LevelIdx != nil {
@@ -82,7 +87,7 @@ func (f *AV1) Marshal() (string, map[string]string) {
fmtp["tier"] = strconv.FormatInt(int64(*f.Tier), 10) fmtp["tier"] = strconv.FormatInt(int64(*f.Tier), 10)
} }
return "AV1/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -13,6 +13,5 @@ func TestAV1Attributes(t *testing.T) {
} }
require.Equal(t, "AV1", format.String()) require.Equal(t, "AV1", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(100), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -19,6 +19,8 @@ func getCodecAndClock(rtpMap string) (string, string) {
// Format is a RTP format of a media. // Format is a RTP format of a media.
// It defines a codec and a payload type used to transmit the media. // It defines a codec and a payload type used to transmit the media.
type Format interface { type Format interface {
unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error
// String returns a description of the format. // String returns a description of the format.
String() string String() string
@@ -28,10 +30,11 @@ type Format interface {
// PayloadType returns the payload type. // PayloadType returns the payload type.
PayloadType() uint8 PayloadType() uint8
unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error // RTPMap returns the rtpmap attribute.
RTPMap() string
// Marshal encodes the format in SDP format. // FMTP returns the fmtp attribute.
Marshal() (string, map[string]string) FMTP() map[string]string
// PTSEqualsDTS checks whether PTS is equal to DTS in RTP packets. // PTSEqualsDTS checks whether PTS is equal to DTS in RTP packets.
PTSEqualsDTS(*rtp.Packet) bool PTSEqualsDTS(*rtp.Packet) bool

View File

@@ -609,7 +609,7 @@ var casesFormat = []struct {
nil, nil,
&Generic{ &Generic{
PayloadTyp: 98, PayloadTyp: 98,
RTPMap: "MetaData/80000", RTPMa: "MetaData/80000",
ClockRat: 80000, ClockRat: 80000,
}, },
"MetaData/80000", "MetaData/80000",
@@ -635,7 +635,7 @@ var casesFormat = []struct {
nil, nil,
&Generic{ &Generic{
PayloadTyp: 98, PayloadTyp: 98,
RTPMap: "custom", RTPMa: "custom",
}, },
"custom", "custom",
nil, nil,
@@ -648,7 +648,7 @@ var casesFormat = []struct {
nil, nil,
&Generic{ &Generic{
PayloadTyp: 98, PayloadTyp: 98,
RTPMap: "custom/aaa", RTPMa: "custom/aaa",
}, },
"custom/aaa", "custom/aaa",
nil, nil,
@@ -668,10 +668,9 @@ func TestUnmarshal(t *testing.T) {
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {
for _, ca := range casesFormat { for _, ca := range casesFormat {
t.Run(ca.name, func(t *testing.T) { t.Run(ca.name, func(t *testing.T) {
rtpMap, fmtp := ca.dec.Marshal()
require.Equal(t, ca.payloadType, ca.dec.PayloadType()) require.Equal(t, ca.payloadType, ca.dec.PayloadType())
require.Equal(t, ca.encRtpMap, rtpMap) require.Equal(t, ca.encRtpMap, ca.dec.RTPMap())
require.Equal(t, ca.encFmtp, fmtp) require.Equal(t, ca.encFmtp, ca.dec.FMTP())
}) })
} }
} }

View File

@@ -13,6 +13,11 @@ type G711 struct {
MULaw bool MULaw bool
} }
func (f *G711) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.MULaw = (payloadType == 0)
return nil
}
// String implements Format. // String implements Format.
func (f *G711) String() string { func (f *G711) String() string {
return "G711" return "G711"
@@ -31,17 +36,17 @@ func (f *G711) PayloadType() uint8 {
return 8 return 8
} }
func (f *G711) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { // RTPMap implements Format.
f.MULaw = (payloadType == 0) func (f *G711) RTPMap() string {
return nil if f.MULaw {
return "PCMU/8000"
}
return "PCMA/8000"
} }
// Marshal implements Format. // FMTP implements Format.
func (f *G711) Marshal() (string, map[string]string) { func (f *G711) FMTP() map[string]string {
if f.MULaw { return nil
return "PCMU/8000", nil
}
return "PCMA/8000", nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,7 +11,6 @@ func TestG711Attributes(t *testing.T) {
format := &G711{} format := &G711{}
require.Equal(t, "G711", format.String()) require.Equal(t, "G711", format.String())
require.Equal(t, 8000, format.ClockRate()) require.Equal(t, 8000, format.ClockRate())
require.Equal(t, uint8(8), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
format = &G711{ format = &G711{
@@ -19,7 +18,6 @@ func TestG711Attributes(t *testing.T) {
} }
require.Equal(t, "G711", format.String()) require.Equal(t, "G711", format.String())
require.Equal(t, 8000, format.ClockRate()) require.Equal(t, 8000, format.ClockRate())
require.Equal(t, uint8(0), format.PayloadType())
} }
func TestG711DecEncoder(t *testing.T) { func TestG711DecEncoder(t *testing.T) {

View File

@@ -10,6 +10,10 @@ import (
// Specification: https://datatracker.ietf.org/doc/html/rfc3551 // Specification: https://datatracker.ietf.org/doc/html/rfc3551
type G722 struct{} type G722 struct{}
func (f *G722) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
return nil
}
// String implements Format. // String implements Format.
func (f *G722) String() string { func (f *G722) String() string {
return "G722" return "G722"
@@ -25,13 +29,14 @@ func (f *G722) PayloadType() uint8 {
return 9 return 9
} }
func (f *G722) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { // RTPMap implements Format.
return nil func (f *G722) RTPMap() string {
return "G722/8000"
} }
// Marshal implements Format. // FMTP implements Format.
func (f *G722) Marshal() (string, map[string]string) { func (f *G722) FMTP() map[string]string {
return "G722/8000", nil return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,7 +11,6 @@ func TestG722Attributes(t *testing.T) {
format := &G722{} format := &G722{}
require.Equal(t, "G722", format.String()) require.Equal(t, "G722", format.String())
require.Equal(t, 8000, format.ClockRate()) require.Equal(t, 8000, format.ClockRate())
require.Equal(t, uint8(9), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -54,8 +54,8 @@ func findClockRate(payloadType uint8, rtpMap string) (int, error) {
// Generic is a generic RTP format. // Generic is a generic RTP format.
type Generic struct { type Generic struct {
PayloadTyp uint8 PayloadTyp uint8
RTPMap string RTPMa string
FMTP map[string]string FMT map[string]string
// clock rate of the format. Filled automatically. // clock rate of the format. Filled automatically.
ClockRat int ClockRat int
@@ -63,10 +63,21 @@ type Generic struct {
// Init computes the clock rate of the format. It it mandatory to call it. // Init computes the clock rate of the format. It it mandatory to call it.
func (f *Generic) Init() error { func (f *Generic) Init() error {
f.ClockRat, _ = findClockRate(f.PayloadTyp, f.RTPMap) f.ClockRat, _ = findClockRate(f.PayloadTyp, f.RTPMa)
return nil return nil
} }
func (f *Generic) unmarshal(
payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string,
) error {
f.PayloadTyp = payloadType
f.RTPMa = rtpmap
f.FMT = fmtp
return f.Init()
}
// String returns a description of the format. // String returns a description of the format.
func (f *Generic) String() string { func (f *Generic) String() string {
return "Generic" return "Generic"
@@ -82,20 +93,14 @@ func (f *Generic) PayloadType() uint8 {
return f.PayloadTyp return f.PayloadTyp
} }
func (f *Generic) unmarshal( // RTPMap implements Format.
payloadType uint8, clock string, codec string, func (f *Generic) RTPMap() string {
rtpmap string, fmtp map[string]string, return f.RTPMa
) error {
f.PayloadTyp = payloadType
f.RTPMap = rtpmap
f.FMTP = fmtp
return f.Init()
} }
// Marshal implements Format. // FMTP implements Format.
func (f *Generic) Marshal() (string, map[string]string) { func (f *Generic) FMTP() map[string]string {
return f.RTPMap, f.FMTP return f.FMT
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -10,8 +10,8 @@ import (
func TestGenericAttributes(t *testing.T) { func TestGenericAttributes(t *testing.T) {
format := &Generic{ format := &Generic{
PayloadTyp: 98, PayloadTyp: 98,
RTPMap: "H265/90000", RTPMa: "H265/90000",
FMTP: map[string]string{ FMT: map[string]string{
"profile-id": "1", "profile-id": "1",
"sprop-vps": "QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ", "sprop-vps": "QAEMAf//AWAAAAMAAAMAAAMAAAMAlqwJ",
"sprop-sps": "QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=", "sprop-sps": "QgEBAWAAAAMAAAMAAAMAAAMAlqADwIAQ5Za5JMmuWcBSSgAAB9AAAHUwgkA=",
@@ -23,6 +23,5 @@ func TestGenericAttributes(t *testing.T) {
require.Equal(t, "Generic", format.String()) require.Equal(t, "Generic", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(98), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -81,21 +81,6 @@ type H264 struct {
mutex sync.RWMutex mutex sync.RWMutex
} }
// String implements Formaf.
func (f *H264) String() string {
return "H264"
}
// ClockRate implements Formaf.
func (f *H264) ClockRate() int {
return 90000
}
// PayloadType implements Formaf.
func (f *H264) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *H264) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *H264) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -131,8 +116,28 @@ func (f *H264) unmarshal(payloadType uint8, clock string, codec string, rtpmap s
return nil return nil
} }
// Marshal implements Formaf. // String implements Format.
func (f *H264) Marshal() (string, map[string]string) { func (f *H264) String() string {
return "H264"
}
// ClockRate implements Format.
func (f *H264) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *H264) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *H264) RTPMap() string {
return "H264/90000"
}
// FMTP implements Format.
func (f *H264) FMTP() map[string]string {
f.mutex.RLock() f.mutex.RLock()
defer f.mutex.RUnlock() defer f.mutex.RUnlock()
@@ -156,10 +161,10 @@ func (f *H264) Marshal() (string, map[string]string) {
fmtp["profile-level-id"] = strings.ToUpper(hex.EncodeToString(f.SPS[1:4])) fmtp["profile-level-id"] = strings.ToUpper(hex.EncodeToString(f.SPS[1:4]))
} }
return "H264/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Formaf. // PTSEqualsDTS implements Format.
func (f *H264) PTSEqualsDTS(pkt *rtp.Packet) bool { func (f *H264) PTSEqualsDTS(pkt *rtp.Packet) bool {
return rtpH264ContainsIDR(pkt) return rtpH264ContainsIDR(pkt)
} }

View File

@@ -16,7 +16,6 @@ func TestH264Attributes(t *testing.T) {
} }
require.Equal(t, "H264", format.String()) require.Equal(t, "H264", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
sps, pps := format.SafeParams() sps, pps := format.SafeParams()
require.Equal(t, []byte{0x01, 0x02}, sps) require.Equal(t, []byte{0x01, 0x02}, sps)

View File

@@ -23,21 +23,6 @@ type H265 struct {
mutex sync.RWMutex mutex sync.RWMutex
} }
// String implements Formaf.
func (f *H265) String() string {
return "H265"
}
// ClockRate implements Formaf.
func (f *H265) ClockRate() int {
return 90000
}
// PayloadType implements Formaf.
func (f *H265) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *H265) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *H265) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -76,8 +61,28 @@ func (f *H265) unmarshal(payloadType uint8, clock string, codec string, rtpmap s
return nil return nil
} }
// Marshal implements Formaf. // String implements Format.
func (f *H265) Marshal() (string, map[string]string) { func (f *H265) String() string {
return "H265"
}
// ClockRate implements Format.
func (f *H265) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *H265) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *H265) RTPMap() string {
return "H265/90000"
}
// FMTP implements Format.
func (f *H265) FMTP() map[string]string {
f.mutex.RLock() f.mutex.RLock()
defer f.mutex.RUnlock() defer f.mutex.RUnlock()
@@ -95,10 +100,10 @@ func (f *H265) Marshal() (string, map[string]string) {
fmtp["sprop-max-don-diff"] = strconv.FormatInt(int64(f.MaxDONDiff), 10) fmtp["sprop-max-don-diff"] = strconv.FormatInt(int64(f.MaxDONDiff), 10)
} }
return "H265/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Formaf. // PTSEqualsDTS implements Format.
func (f *H265) PTSEqualsDTS(*rtp.Packet) bool { func (f *H265) PTSEqualsDTS(*rtp.Packet) bool {
return true return true
} }

View File

@@ -16,7 +16,6 @@ func TestH265Attributes(t *testing.T) {
} }
require.Equal(t, "H265", format.String()) require.Equal(t, "H265", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
vps, sps, pps := format.SafeParams() vps, sps, pps := format.SafeParams()

View File

@@ -18,21 +18,6 @@ type LPCM struct {
ChannelCount int ChannelCount int
} }
// String implements Format.
func (f *LPCM) String() string {
return "LPCM"
}
// ClockRate implements Format.
func (f *LPCM) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *LPCM) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -68,8 +53,23 @@ func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, rtpmap s
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *LPCM) Marshal() (string, map[string]string) { func (f *LPCM) String() string {
return "LPCM"
}
// ClockRate implements Format.
func (f *LPCM) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *LPCM) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *LPCM) RTPMap() string {
var codec string var codec string
switch f.BitDepth { switch f.BitDepth {
case 8: case 8:
@@ -83,7 +83,12 @@ func (f *LPCM) Marshal() (string, map[string]string) {
} }
return codec + "/" + strconv.FormatInt(int64(f.SampleRate), 10) + return codec + "/" + strconv.FormatInt(int64(f.SampleRate), 10) +
"/" + strconv.FormatInt(int64(f.ChannelCount), 10), nil "/" + strconv.FormatInt(int64(f.ChannelCount), 10)
}
// FMTP implements Format.
func (f *LPCM) FMTP() map[string]string {
return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -16,7 +16,6 @@ func TestLPCMAttributes(t *testing.T) {
} }
require.Equal(t, "LPCM", format.String()) require.Equal(t, "LPCM", format.String())
require.Equal(t, 44100, format.ClockRate()) require.Equal(t, 44100, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -10,6 +10,10 @@ import (
// Specification: https://datatracker.ietf.org/doc/html/rfc2435 // Specification: https://datatracker.ietf.org/doc/html/rfc2435
type MJPEG struct{} type MJPEG struct{}
func (f *MJPEG) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
return nil
}
// String implements Format. // String implements Format.
func (f *MJPEG) String() string { func (f *MJPEG) String() string {
return "M-JPEG" return "M-JPEG"
@@ -25,13 +29,14 @@ func (f *MJPEG) PayloadType() uint8 {
return 26 return 26
} }
func (f *MJPEG) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { // RTPMap implements Format.
return nil func (f *MJPEG) RTPMap() string {
return "JPEG/90000"
} }
// Marshal implements Format. // FMTP implements Format.
func (f *MJPEG) Marshal() (string, map[string]string) { func (f *MJPEG) FMTP() map[string]string {
return "JPEG/90000", nil return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,7 +11,6 @@ func TestMJPEGAttributes(t *testing.T) {
format := &MJPEG{} format := &MJPEG{}
require.Equal(t, "M-JPEG", format.String()) require.Equal(t, "M-JPEG", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(26), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -8,6 +8,13 @@ import (
// Specification: https://datatracker.ietf.org/doc/html/rfc2250 // Specification: https://datatracker.ietf.org/doc/html/rfc2250
type MPEG2Audio struct{} type MPEG2Audio struct{}
func (f *MPEG2Audio) unmarshal(
payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string,
) error {
return nil
}
// String implements Format. // String implements Format.
func (f *MPEG2Audio) String() string { func (f *MPEG2Audio) String() string {
return "MPEG2-audio" return "MPEG2-audio"
@@ -23,16 +30,14 @@ func (f *MPEG2Audio) PayloadType() uint8 {
return 14 return 14
} }
func (f *MPEG2Audio) unmarshal( // RTPMap implements Format.
payloadType uint8, clock string, codec string, func (f *MPEG2Audio) RTPMap() string {
rtpmap string, fmtp map[string]string, return ""
) error {
return nil
} }
// Marshal implements Format. // FMTP implements Format.
func (f *MPEG2Audio) Marshal() (string, map[string]string) { func (f *MPEG2Audio) FMTP() map[string]string {
return "", nil return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,6 +11,5 @@ func TestMPEG2AudioAttributes(t *testing.T) {
format := &MPEG2Audio{} format := &MPEG2Audio{}
require.Equal(t, "MPEG2-audio", format.String()) require.Equal(t, "MPEG2-audio", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(14), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -8,6 +8,13 @@ import (
// Specification: https://datatracker.ietf.org/doc/html/rfc2250 // Specification: https://datatracker.ietf.org/doc/html/rfc2250
type MPEG2Video struct{} type MPEG2Video struct{}
func (f *MPEG2Video) unmarshal(
payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string,
) error {
return nil
}
// String implements Format. // String implements Format.
func (f *MPEG2Video) String() string { func (f *MPEG2Video) String() string {
return "MPEG2-video" return "MPEG2-video"
@@ -23,16 +30,14 @@ func (f *MPEG2Video) PayloadType() uint8 {
return 32 return 32
} }
func (f *MPEG2Video) unmarshal( // RTPMap implements Format.
payloadType uint8, clock string, codec string, func (f *MPEG2Video) RTPMap() string {
rtpmap string, fmtp map[string]string, return ""
) error {
return nil
} }
// Marshal implements Format. // FMTP implements Format.
func (f *MPEG2Video) Marshal() (string, map[string]string) { func (f *MPEG2Video) FMTP() map[string]string {
return "", nil return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,6 +11,5 @@ func TestMPEG2VideoAttributes(t *testing.T) {
format := &MPEG2Video{} format := &MPEG2Video{}
require.Equal(t, "MPEG2-video", format.String()) require.Equal(t, "MPEG2-video", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(32), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -26,21 +26,6 @@ type MPEG4AudioGeneric struct {
IndexDeltaLength int IndexDeltaLength int
} }
// String implements Format.
func (f *MPEG4AudioGeneric) String() string {
return "MPEG4-audio-gen"
}
// ClockRate implements Format.
func (f *MPEG4AudioGeneric) ClockRate() int {
return f.Config.SampleRate
}
// PayloadType implements Format.
func (f *MPEG4AudioGeneric) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *MPEG4AudioGeneric) unmarshal( func (f *MPEG4AudioGeneric) unmarshal(
payloadType uint8, clock string, codec string, payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string, rtpmap string, fmtp map[string]string,
@@ -113,18 +98,39 @@ func (f *MPEG4AudioGeneric) unmarshal(
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *MPEG4AudioGeneric) Marshal() (string, map[string]string) { func (f *MPEG4AudioGeneric) String() string {
enc, err := f.Config.Marshal() return "MPEG4-audio-gen"
if err != nil {
return "", nil
} }
// ClockRate implements Format.
func (f *MPEG4AudioGeneric) ClockRate() int {
return f.Config.SampleRate
}
// PayloadType implements Format.
func (f *MPEG4AudioGeneric) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *MPEG4AudioGeneric) RTPMap() string {
sampleRate := f.Config.SampleRate sampleRate := f.Config.SampleRate
if f.Config.ExtensionSampleRate != 0 { if f.Config.ExtensionSampleRate != 0 {
sampleRate = f.Config.ExtensionSampleRate sampleRate = f.Config.ExtensionSampleRate
} }
return "mpeg4-generic/" + strconv.FormatInt(int64(sampleRate), 10) +
"/" + strconv.FormatInt(int64(f.Config.ChannelCount), 10)
}
// FMTP implements Format.
func (f *MPEG4AudioGeneric) FMTP() map[string]string {
enc, err := f.Config.Marshal()
if err != nil {
return nil
}
profileLevelID := f.ProfileLevelID profileLevelID := f.ProfileLevelID
if profileLevelID == 0 { // support legacy definition which didn't include profile-level-id if profileLevelID == 0 { // support legacy definition which didn't include profile-level-id
profileLevelID = 1 profileLevelID = 1
@@ -150,8 +156,7 @@ func (f *MPEG4AudioGeneric) Marshal() (string, map[string]string) {
fmtp["config"] = hex.EncodeToString(enc) fmtp["config"] = hex.EncodeToString(enc)
return "mpeg4-generic/" + strconv.FormatInt(int64(sampleRate), 10) + return fmtp
"/" + strconv.FormatInt(int64(f.Config.ChannelCount), 10), fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -23,7 +23,6 @@ func TestMPEG4AudioGenericAttributes(t *testing.T) {
} }
require.Equal(t, "MPEG4-audio-gen", format.String()) require.Equal(t, "MPEG4-audio-gen", format.String())
require.Equal(t, 48000, format.ClockRate()) require.Equal(t, 48000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -24,21 +24,6 @@ type MPEG4AudioLATM struct {
SBREnabled *bool SBREnabled *bool
} }
// String implements Format.
func (f *MPEG4AudioLATM) String() string {
return "MPEG4-audio-latm"
}
// ClockRate implements Format.
func (f *MPEG4AudioLATM) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *MPEG4AudioLATM) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *MPEG4AudioLATM) unmarshal( func (f *MPEG4AudioLATM) unmarshal(
payloadType uint8, clock string, codec string, payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string, rtpmap string, fmtp map[string]string,
@@ -135,8 +120,29 @@ func (f *MPEG4AudioLATM) unmarshal(
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *MPEG4AudioLATM) Marshal() (string, map[string]string) { func (f *MPEG4AudioLATM) String() string {
return "MPEG4-audio-latm"
}
// ClockRate implements Format.
func (f *MPEG4AudioLATM) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *MPEG4AudioLATM) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *MPEG4AudioLATM) RTPMap() string {
return "MP4A-LATM/" + strconv.FormatInt(int64(f.SampleRate), 10) +
"/" + strconv.FormatInt(int64(f.Channels), 10)
}
// FMTP implements Format.
func (f *MPEG4AudioLATM) FMTP() map[string]string {
fmtp := map[string]string{ fmtp := map[string]string{
"profile-level-id": strconv.FormatInt(int64(f.ProfileLevelID), 10), "profile-level-id": strconv.FormatInt(int64(f.ProfileLevelID), 10),
"config": hex.EncodeToString(f.Config), "config": hex.EncodeToString(f.Config),
@@ -163,8 +169,7 @@ func (f *MPEG4AudioLATM) Marshal() (string, map[string]string) {
} }
} }
return "MP4A-LATM/" + strconv.FormatInt(int64(f.SampleRate), 10) + return fmtp
"/" + strconv.FormatInt(int64(f.Channels), 10), fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -18,6 +18,5 @@ func TestMPEG4AudioLATMAttributes(t *testing.T) {
} }
require.Equal(t, "MPEG4-audio-latm", format.String()) require.Equal(t, "MPEG4-audio-latm", format.String())
require.Equal(t, 48000, format.ClockRate()) require.Equal(t, 48000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -20,21 +20,6 @@ type MPEG4VideoES struct {
Config []byte Config []byte
} }
// String implements Format.
func (f *MPEG4VideoES) String() string {
return "MPEG4-video-es"
}
// ClockRate implements Format.
func (f *MPEG4VideoES) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *MPEG4VideoES) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *MPEG4VideoES) unmarshal( func (f *MPEG4VideoES) unmarshal(
payloadType uint8, clock string, codec string, payloadType uint8, clock string, codec string,
rtpmap string, fmtp map[string]string, rtpmap string, fmtp map[string]string,
@@ -64,14 +49,34 @@ func (f *MPEG4VideoES) unmarshal(
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *MPEG4VideoES) Marshal() (string, map[string]string) { func (f *MPEG4VideoES) String() string {
return "MPEG4-video-es"
}
// ClockRate implements Format.
func (f *MPEG4VideoES) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *MPEG4VideoES) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *MPEG4VideoES) RTPMap() string {
return "MP4V-ES/90000"
}
// FMTP implements Format.
func (f *MPEG4VideoES) FMTP() map[string]string {
fmtp := map[string]string{ fmtp := map[string]string{
"profile-level-id": strconv.FormatInt(int64(f.ProfileLevelID), 10), "profile-level-id": strconv.FormatInt(int64(f.ProfileLevelID), 10),
"config": strings.ToUpper(hex.EncodeToString(f.Config)), "config": strings.ToUpper(hex.EncodeToString(f.Config)),
} }
return "MP4V-ES/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -15,6 +15,5 @@ func TestMPEG4VideoESAttributes(t *testing.T) {
} }
require.Equal(t, "MPEG4-video-es", format.String()) require.Equal(t, "MPEG4-video-es", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -8,6 +8,10 @@ import (
// Specification: https://datatracker.ietf.org/doc/html/rfc2250 // Specification: https://datatracker.ietf.org/doc/html/rfc2250
type MPEGTS struct{} type MPEGTS struct{}
func (f *MPEGTS) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
return nil
}
// String implements Format. // String implements Format.
func (f *MPEGTS) String() string { func (f *MPEGTS) String() string {
return "MPEG-TS" return "MPEG-TS"
@@ -23,13 +27,14 @@ func (f *MPEGTS) PayloadType() uint8 {
return 33 return 33
} }
func (f *MPEGTS) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { // RTPMap implements Format.
return nil func (f *MPEGTS) RTPMap() string {
return "MP2T/90000"
} }
// Marshal implements Format. // FMTP implements Format.
func (f *MPEGTS) Marshal() (string, map[string]string) { func (f *MPEGTS) FMTP() map[string]string {
return "MP2T/90000", nil return nil
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -11,6 +11,5 @@ func TestMPEGTSAttributes(t *testing.T) {
format := &MPEGTS{} format := &MPEGTS{}
require.Equal(t, "MPEG-TS", format.String()) require.Equal(t, "MPEG-TS", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(33), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -17,23 +17,6 @@ type Opus struct {
IsStereo bool IsStereo bool
} }
// String implements Format.
func (f *Opus) String() string {
return "Opus"
}
// ClockRate implements Format.
func (f *Opus) ClockRate() int {
// RFC7587: the RTP timestamp is incremented with a 48000 Hz
// clock rate for all modes of Opus and all sampling rates.
return 48000
}
// PayloadType implements Format.
func (f *Opus) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *Opus) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *Opus) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -61,8 +44,32 @@ func (f *Opus) unmarshal(payloadType uint8, clock string, codec string, rtpmap s
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *Opus) Marshal() (string, map[string]string) { func (f *Opus) String() string {
return "Opus"
}
// ClockRate implements Format.
func (f *Opus) ClockRate() int {
// RFC7587: the RTP timestamp is incremented with a 48000 Hz
// clock rate for all modes of Opus and all sampling rates.
return 48000
}
// PayloadType implements Format.
func (f *Opus) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *Opus) RTPMap() string {
// RFC7587: The RTP clock rate in "a=rtpmap" MUST be 48000, and the
// number of channels MUST be 2.
return "opus/48000/2"
}
// FMTP implements Format.
func (f *Opus) FMTP() map[string]string {
fmtp := map[string]string{ fmtp := map[string]string{
"sprop-stereo": func() string { "sprop-stereo": func() string {
if f.IsStereo { if f.IsStereo {
@@ -71,10 +78,7 @@ func (f *Opus) Marshal() (string, map[string]string) {
return "0" return "0"
}(), }(),
} }
return fmtp
// RFC7587: The RTP clock rate in "a=rtpmap" MUST be 48000, and the
// number of channels MUST be 2.
return "opus/48000/2", fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -14,7 +14,6 @@ func TestOpusAttributes(t *testing.T) {
} }
require.Equal(t, "Opus", format.String()) require.Equal(t, "Opus", format.String())
require.Equal(t, 48000, format.ClockRate()) require.Equal(t, 48000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -18,21 +18,6 @@ type Vorbis struct {
Configuration []byte Configuration []byte
} }
// String implements Format.
func (f *Vorbis) String() string {
return "Vorbis"
}
// ClockRate implements Format.
func (f *Vorbis) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *Vorbis) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *Vorbis) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *Vorbis) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -71,15 +56,34 @@ func (f *Vorbis) unmarshal(payloadType uint8, clock string, codec string, rtpmap
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *Vorbis) Marshal() (string, map[string]string) { func (f *Vorbis) String() string {
return "Vorbis"
}
// ClockRate implements Format.
func (f *Vorbis) ClockRate() int {
return f.SampleRate
}
// PayloadType implements Format.
func (f *Vorbis) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *Vorbis) RTPMap() string {
return "VORBIS/" + strconv.FormatInt(int64(f.SampleRate), 10) +
"/" + strconv.FormatInt(int64(f.ChannelCount), 10)
}
// FMTP implements Format.
func (f *Vorbis) FMTP() map[string]string {
fmtp := map[string]string{ fmtp := map[string]string{
"configuration": base64.StdEncoding.EncodeToString(f.Configuration), "configuration": base64.StdEncoding.EncodeToString(f.Configuration),
} }
return "VORBIS/" + strconv.FormatInt(int64(f.SampleRate), 10) + return fmtp
"/" + strconv.FormatInt(int64(f.ChannelCount), 10),
fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -16,6 +16,5 @@ func TestVorbisAttributes(t *testing.T) {
} }
require.Equal(t, "Vorbis", format.String()) require.Equal(t, "Vorbis", format.String())
require.Equal(t, 48000, format.ClockRate()) require.Equal(t, 48000, format.ClockRate())
require.Equal(t, uint8(96), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -17,21 +17,6 @@ type VP8 struct {
MaxFS *int MaxFS *int
} }
// String implements Format.
func (f *VP8) String() string {
return "VP8"
}
// ClockRate implements Format.
func (f *VP8) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *VP8) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *VP8) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *VP8) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -60,8 +45,28 @@ func (f *VP8) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *VP8) Marshal() (string, map[string]string) { func (f *VP8) String() string {
return "VP8"
}
// ClockRate implements Format.
func (f *VP8) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *VP8) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *VP8) RTPMap() string {
return "VP8/90000"
}
// FMTP implements Format.
func (f *VP8) FMTP() map[string]string {
fmtp := make(map[string]string) fmtp := make(map[string]string)
if f.MaxFR != nil { if f.MaxFR != nil {
@@ -72,7 +77,7 @@ func (f *VP8) Marshal() (string, map[string]string) {
fmtp["max-fs"] = strconv.FormatInt(int64(*f.MaxFS), 10) fmtp["max-fs"] = strconv.FormatInt(int64(*f.MaxFS), 10)
} }
return "VP8/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -13,7 +13,6 @@ func TestVP8ttributes(t *testing.T) {
} }
require.Equal(t, "VP8", format.String()) require.Equal(t, "VP8", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(99), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -18,21 +18,6 @@ type VP9 struct {
ProfileID *int ProfileID *int
} }
// String implements Format.
func (f *VP9) String() string {
return "VP9"
}
// ClockRate implements Format.
func (f *VP9) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *VP9) PayloadType() uint8 {
return f.PayloadTyp
}
func (f *VP9) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error { func (f *VP9) unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error {
f.PayloadTyp = payloadType f.PayloadTyp = payloadType
@@ -70,8 +55,28 @@ func (f *VP9) unmarshal(payloadType uint8, clock string, codec string, rtpmap st
return nil return nil
} }
// Marshal implements Format. // String implements Format.
func (f *VP9) Marshal() (string, map[string]string) { func (f *VP9) String() string {
return "VP9"
}
// ClockRate implements Format.
func (f *VP9) ClockRate() int {
return 90000
}
// PayloadType implements Format.
func (f *VP9) PayloadType() uint8 {
return f.PayloadTyp
}
// RTPMap implements Format.
func (f *VP9) RTPMap() string {
return "VP9/90000"
}
// FMTP implements Format.
func (f *VP9) FMTP() map[string]string {
fmtp := make(map[string]string) fmtp := make(map[string]string)
if f.MaxFR != nil { if f.MaxFR != nil {
@@ -84,7 +89,7 @@ func (f *VP9) Marshal() (string, map[string]string) {
fmtp["profile-id"] = strconv.FormatInt(int64(*f.ProfileID), 10) fmtp["profile-id"] = strconv.FormatInt(int64(*f.ProfileID), 10)
} }
return "VP9/90000", fmtp return fmtp
} }
// PTSEqualsDTS implements Format. // PTSEqualsDTS implements Format.

View File

@@ -13,7 +13,6 @@ func TestVP9Attributes(t *testing.T) {
} }
require.Equal(t, "VP9", format.String()) require.Equal(t, "VP9", format.String())
require.Equal(t, 90000, format.ClockRate()) require.Equal(t, 90000, format.ClockRate())
require.Equal(t, uint8(100), format.PayloadType())
require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{})) require.Equal(t, true, format.PTSEqualsDTS(&rtp.Packet{}))
} }

View File

@@ -78,6 +78,17 @@ func decodeFMTP(enc string) map[string]string {
return ret return ret
} }
func sortedKeys(fmtp map[string]string) []string {
keys := make([]string, len(fmtp))
i := 0
for key := range fmtp {
keys[i] = key
i++
}
sort.Strings(keys)
return keys
}
// Direction is the direction of a media stream. // Direction is the direction of a media stream.
type Direction string type Direction string
@@ -182,8 +193,7 @@ func (m Media) Marshal() *psdp.MediaDescription {
typ := strconv.FormatUint(uint64(forma.PayloadType()), 10) typ := strconv.FormatUint(uint64(forma.PayloadType()), 10)
md.MediaName.Formats = append(md.MediaName.Formats, typ) md.MediaName.Formats = append(md.MediaName.Formats, typ)
rtpmap, fmtp := forma.Marshal() rtpmap := forma.RTPMap()
if rtpmap != "" { if rtpmap != "" {
md.Attributes = append(md.Attributes, psdp.Attribute{ md.Attributes = append(md.Attributes, psdp.Attribute{
Key: "rtpmap", Key: "rtpmap",
@@ -191,17 +201,10 @@ func (m Media) Marshal() *psdp.MediaDescription {
}) })
} }
fmtp := forma.FMTP()
if len(fmtp) != 0 { if len(fmtp) != 0 {
keys := make([]string, len(fmtp))
i := 0
for key := range fmtp {
keys[i] = key
i++
}
sort.Strings(keys)
tmp := make([]string, len(fmtp)) tmp := make([]string, len(fmtp))
for i, key := range keys { for i, key := range sortedKeys(fmtp) {
tmp[i] = key + "=" + fmtp[key] tmp[i] = key + "=" + fmtp[key]
} }

View File

@@ -302,18 +302,18 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 103, PayloadTyp: 103,
RTPMap: "ISAC/16000", RTPMa: "ISAC/16000",
ClockRat: 16000, ClockRat: 16000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 104, PayloadTyp: 104,
RTPMap: "ISAC/32000", RTPMa: "ISAC/32000",
ClockRat: 32000, ClockRat: 32000,
}, },
&formats.G722{}, &formats.G722{},
&formats.Generic{ &formats.Generic{
PayloadTyp: 102, PayloadTyp: 102,
RTPMap: "ILBC/8000", RTPMa: "ILBC/8000",
ClockRat: 8000, ClockRat: 8000,
}, },
&formats.G711{ &formats.G711{
@@ -324,37 +324,37 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 106, PayloadTyp: 106,
RTPMap: "CN/32000", RTPMa: "CN/32000",
ClockRat: 32000, ClockRat: 32000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 105, PayloadTyp: 105,
RTPMap: "CN/16000", RTPMa: "CN/16000",
ClockRat: 16000, ClockRat: 16000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 13, PayloadTyp: 13,
RTPMap: "CN/8000", RTPMa: "CN/8000",
ClockRat: 8000, ClockRat: 8000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 110, PayloadTyp: 110,
RTPMap: "telephone-event/48000", RTPMa: "telephone-event/48000",
ClockRat: 48000, ClockRat: 48000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 112, PayloadTyp: 112,
RTPMap: "telephone-event/32000", RTPMa: "telephone-event/32000",
ClockRat: 32000, ClockRat: 32000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 113, PayloadTyp: 113,
RTPMap: "telephone-event/16000", RTPMa: "telephone-event/16000",
ClockRat: 16000, ClockRat: 16000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 126, PayloadTyp: 126,
RTPMap: "telephone-event/8000", RTPMa: "telephone-event/8000",
ClockRat: 8000, ClockRat: 8000,
}, },
}, },
@@ -368,8 +368,8 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 97, PayloadTyp: 97,
RTPMap: "rtx/90000", RTPMa: "rtx/90000",
FMTP: map[string]string{ FMT: map[string]string{
"apt": "96", "apt": "96",
}, },
ClockRat: 90000, ClockRat: 90000,
@@ -379,8 +379,8 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 99, PayloadTyp: 99,
RTPMap: "rtx/90000", RTPMa: "rtx/90000",
FMTP: map[string]string{ FMT: map[string]string{
"apt": "98", "apt": "98",
}, },
ClockRat: 90000, ClockRat: 90000,
@@ -391,28 +391,28 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 101, PayloadTyp: 101,
RTPMap: "rtx/90000", RTPMa: "rtx/90000",
FMTP: map[string]string{ FMT: map[string]string{
"apt": "100", "apt": "100",
}, },
ClockRat: 90000, ClockRat: 90000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 127, PayloadTyp: 127,
RTPMap: "red/90000", RTPMa: "red/90000",
ClockRat: 90000, ClockRat: 90000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 124, PayloadTyp: 124,
RTPMap: "rtx/90000", RTPMa: "rtx/90000",
FMTP: map[string]string{ FMT: map[string]string{
"apt": "127", "apt": "127",
}, },
ClockRat: 90000, ClockRat: 90000,
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 125, PayloadTyp: 125,
RTPMap: "ulpfec/90000", RTPMa: "ulpfec/90000",
ClockRat: 90000, ClockRat: 90000,
}, },
}, },
@@ -457,7 +457,7 @@ var casesMedias = []struct {
}, },
&formats.Generic{ &formats.Generic{
PayloadTyp: 98, PayloadTyp: 98,
RTPMap: "MetaData", RTPMa: "MetaData",
}, },
}, },
}, },
@@ -537,7 +537,7 @@ var casesMedias = []struct {
Type: "application", Type: "application",
Formats: []formats.Format{&formats.Generic{ Formats: []formats.Format{&formats.Generic{
PayloadTyp: 95, PayloadTyp: 95,
RTPMap: "TP-LINK/90000", RTPMa: "TP-LINK/90000",
ClockRat: 90000, ClockRat: 90000,
}}, }},
}, },
@@ -638,8 +638,8 @@ func TestMediasMarshal(t *testing.T) {
func TestMediasFindFormat(t *testing.T) { func TestMediasFindFormat(t *testing.T) {
tr := &formats.Generic{ tr := &formats.Generic{
PayloadTyp: 97, PayloadTyp: 97,
RTPMap: "rtx/90000", RTPMa: "rtx/90000",
FMTP: map[string]string{ FMT: map[string]string{
"apt": "96", "apt": "96",
}, },
ClockRat: 90000, ClockRat: 90000,

View File

@@ -1833,7 +1833,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) {
forma := &formats.Generic{ forma := &formats.Generic{
PayloadTyp: 96, PayloadTyp: 96,
RTPMap: "private/90000", RTPMa: "private/90000",
} }
err := forma.Init() err := forma.Init()
require.NoError(t, err) require.NoError(t, err)
@@ -1964,7 +1964,7 @@ func TestServerPlayAdditionalInfos(t *testing.T) {
func TestServerPlayNoInterleavedIDs(t *testing.T) { func TestServerPlayNoInterleavedIDs(t *testing.T) {
forma := &formats.Generic{ forma := &formats.Generic{
PayloadTyp: 96, PayloadTyp: 96,
RTPMap: "private/90000", RTPMa: "private/90000",
} }
err := forma.Init() err := forma.Init()
require.NoError(t, err) require.NoError(t, err)

View File

@@ -431,7 +431,7 @@ func TestServerRecordErrorRecordPartialMedias(t *testing.T) {
forma := &formats.Generic{ forma := &formats.Generic{
PayloadTyp: 96, PayloadTyp: 96,
RTPMap: "private/90000", RTPMa: "private/90000",
} }
err = forma.Init() err = forma.Init()
require.NoError(t, err) require.NoError(t, err)
@@ -1263,7 +1263,7 @@ func TestServerRecordDecodeErrors(t *testing.T) {
Type: media.TypeApplication, Type: media.TypeApplication,
Formats: []formats.Format{&formats.Generic{ Formats: []formats.Format{&formats.Generic{
PayloadTyp: 97, PayloadTyp: 97,
RTPMap: "private/90000", RTPMa: "private/90000",
}}, }},
}} }}
resetMediaControls(medias) resetMediaControls(medias)