diff --git a/pkg/format/av1.go b/pkg/format/av1.go index 0916ba19..7f1083c7 100644 --- a/pkg/format/av1.go +++ b/pkg/format/av1.go @@ -18,10 +18,10 @@ type AV1 struct { Tier *int } -func (f *AV1) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *AV1) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "level-idx": n, err := strconv.ParseUint(val, 10, 31) diff --git a/pkg/format/format.go b/pkg/format/format.go index 5690a51f..cc36a18b 100644 --- a/pkg/format/format.go +++ b/pkg/format/format.go @@ -16,10 +16,19 @@ func getCodecAndClock(rtpMap string) (string, string) { return strings.ToLower(parts2[0]), parts2[1] } +type unmarshalContext struct { + mediaType string + payloadType uint8 + clock string + codec string + rtpMap string + fmtp map[string]string +} + // Format is a media format. // It defines the payload type of RTP packets and how to encode/decode them. type Format interface { - unmarshal(payloadType uint8, clock string, codec string, rtpmap string, fmtp map[string]string) error + unmarshal(ctx *unmarshalContext) error // Codec returns the codec name. Codec() string @@ -46,81 +55,86 @@ func Unmarshal(mediaType string, payloadType uint8, rtpMap string, fmtp map[stri format := func() Format { switch { - case mediaType == "video": - switch { - case payloadType == 26: - return &MJPEG{} + // video - case payloadType == 32: - return &MPEG1Video{} + case payloadType == 26: + return &MJPEG{} - case payloadType == 33: - return &MPEGTS{} + case payloadType == 32: + return &MPEG1Video{} - case codec == "mp4v-es" && clock == "90000": - return &MPEG4Video{} + case payloadType == 33: + return &MPEGTS{} - case codec == "h264" && clock == "90000": - return &H264{} + case codec == "mp4v-es" && clock == "90000": + return &MPEG4Video{} - case codec == "h265" && clock == "90000": - return &H265{} + case codec == "h264" && clock == "90000": + return &H264{} - case codec == "vp8" && clock == "90000": - return &VP8{} + case codec == "h265" && clock == "90000": + return &H265{} - case codec == "vp9" && clock == "90000": - return &VP9{} + case codec == "vp8" && clock == "90000": + return &VP8{} - case codec == "av1" && clock == "90000": - return &AV1{} - } + case codec == "vp9" && clock == "90000": + return &VP9{} - case mediaType == "audio": - switch { - case payloadType == 0, payloadType == 8: - return &G711{} + case codec == "av1" && clock == "90000": + return &AV1{} - case payloadType == 9: - return &G722{} + // audio - case (codec == "g726-16" || - codec == "g726-24" || - codec == "g726-32" || - codec == "g726-40" || - codec == "aal2-g726-16" || - codec == "aal2-g726-24" || - codec == "aal2-g726-32" || - codec == "aal2-g726-40") && clock == "8000": - return &G726{} + case payloadType == 0, payloadType == 8: + return &G711{} - case payloadType == 14: - return &MPEG1Audio{} + case payloadType == 9: + return &G722{} - case codec == "l8", codec == "l16", codec == "l24": - return &LPCM{} + case (codec == "g726-16" || + codec == "g726-24" || + codec == "g726-32" || + codec == "g726-40" || + codec == "aal2-g726-16" || + codec == "aal2-g726-24" || + codec == "aal2-g726-32" || + codec == "aal2-g726-40") && clock == "8000": + return &G726{} - case codec == "mpeg4-generic": - return &MPEG4AudioGeneric{} + case payloadType == 14: + return &MPEG1Audio{} - case codec == "mp4a-latm": - return &MPEG4AudioLATM{} + case codec == "l8", codec == "l16", codec == "l24": + return &LPCM{} - case codec == "speex": - return &Speex{} + case codec == "mpeg4-generic": + return &MPEG4AudioGeneric{} - case codec == "vorbis": - return &Vorbis{} + case codec == "mp4a-latm": + return &MPEG4AudioLATM{} - case codec == "opus": - return &Opus{} - } + case codec == "speex": + return &Speex{} + + case codec == "vorbis": + return &Vorbis{} + + case codec == "opus": + return &Opus{} } return &Generic{} }() - err := format.unmarshal(payloadType, clock, codec, rtpMap, fmtp) + err := format.unmarshal(&unmarshalContext{ + mediaType: mediaType, + payloadType: payloadType, + clock: clock, + codec: codec, + rtpMap: rtpMap, + fmtp: fmtp, + }) if err != nil { return nil, err } diff --git a/pkg/format/format_test.go b/pkg/format/format_test.go index d51202d5..af346d30 100644 --- a/pkg/format/format_test.go +++ b/pkg/format/format_test.go @@ -890,19 +890,6 @@ var casesFormat = []struct { "custom", nil, }, - { - "application invalid rtpmap 2", - "application", - 98, - "custom/aaa", - nil, - &Generic{ - PayloadTyp: 98, - RTPMa: "custom/aaa", - }, - "custom/aaa", - nil, - }, } func TestUnmarshal(t *testing.T) { @@ -925,109 +912,116 @@ func TestMarshal(t *testing.T) { } } -func TestUnmarshalMPEG4AudioGenericErrors(t *testing.T) { - _, err := Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "streamtype": "10", +func TestUnmarshalErrors(t *testing.T) { + t.Run("invalid video", func(t *testing.T) { + _, err := Unmarshal("video", 96, "", map[string]string{}) + require.Error(t, err) }) - require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "mode": "asd", - }) - require.Error(t, err) + t.Run("mpeg-4 audio generic", func(t *testing.T) { + _, err := Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "streamtype": "10", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "profile-level-id": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "mode": "asd", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "config": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "profile-level-id": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "config": "0ab2", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "config": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "sizelength": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "config": "0ab2", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "indexlength": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "sizelength": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "indexdeltalength": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "indexlength": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "profile-level-id": "1", - "sizelength": "13", - "indexlength": "3", - "indexdeltalength": "3", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "indexdeltalength": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ - "profile-level-id": "1", - "config": "1190", - "indexlength": "3", - "indexdeltalength": "3", - }) - require.Error(t, err) -} + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "profile-level-id": "1", + "sizelength": "13", + "indexlength": "3", + "indexdeltalength": "3", + }) + require.Error(t, err) -func TestUnmarshalMPEG4AudioLATMErrors(t *testing.T) { - _, err := Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ - "profile-level-id": "aaa", + _, err = Unmarshal("audio", 96, "MPEG4-generic/48000/2", map[string]string{ + "profile-level-id": "1", + "config": "1190", + "indexlength": "3", + "indexdeltalength": "3", + }) + require.Error(t, err) }) - require.Error(t, err) - _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ - "bitrate": "aaa", - }) - require.Error(t, err) + t.Run("mpeg-4 audio latm", func(t *testing.T) { + _, err := Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ + "profile-level-id": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ - "cpresent": "0", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ + "bitrate": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ - "config": "aaa", - }) - require.Error(t, err) + _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ + "cpresent": "0", + }) + require.Error(t, err) - _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ - "profile-level-id": "15", - "object": "2", - "cpresent": "0", - "sbr-enabled": "1", - }) - require.Error(t, err) -} + _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ + "config": "aaa", + }) + require.Error(t, err) -func TestUnmarshalAV1Errors(t *testing.T) { - _, err := Unmarshal("video", 96, "AV1/90000", map[string]string{ - "level-idx": "aaa", + _, err = Unmarshal("audio", 96, "MP4A-LATM/48000/2", map[string]string{ + "profile-level-id": "15", + "object": "2", + "cpresent": "0", + "sbr-enabled": "1", + }) + require.Error(t, err) }) - require.Error(t, err) - _, err = Unmarshal("video", 96, "AV1/90000", map[string]string{ - "profile": "aaa", - }) - require.Error(t, err) + t.Run("av1", func(t *testing.T) { + _, err := Unmarshal("video", 96, "AV1/90000", map[string]string{ + "level-idx": "aaa", + }) + require.Error(t, err) - _, err = Unmarshal("video", 96, "AV1/90000", map[string]string{ - "tier": "aaa", + _, err = Unmarshal("video", 96, "AV1/90000", map[string]string{ + "profile": "aaa", + }) + require.Error(t, err) + + _, err = Unmarshal("video", 96, "AV1/90000", map[string]string{ + "tier": "aaa", + }) + require.Error(t, err) }) - require.Error(t, err) } func FuzzUnmarshalH264(f *testing.F) { diff --git a/pkg/format/g711.go b/pkg/format/g711.go index f99f196b..23abf4c0 100644 --- a/pkg/format/g711.go +++ b/pkg/format/g711.go @@ -13,8 +13,8 @@ type G711 struct { MULaw bool } -func (f *G711) unmarshal(payloadType uint8, _ string, _ string, _ string, _ map[string]string) error { - f.MULaw = (payloadType == 0) +func (f *G711) unmarshal(ctx *unmarshalContext) error { + f.MULaw = (ctx.payloadType == 0) return nil } diff --git a/pkg/format/g722.go b/pkg/format/g722.go index 5751abed..53f17cbc 100644 --- a/pkg/format/g722.go +++ b/pkg/format/g722.go @@ -10,7 +10,7 @@ import ( // Specification: https://datatracker.ietf.org/doc/html/rfc3551 type G722 struct{} -func (f *G722) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error { +func (f *G722) unmarshal(_ *unmarshalContext) error { return nil } diff --git a/pkg/format/g726.go b/pkg/format/g726.go index cec444ac..a602d4f8 100644 --- a/pkg/format/g726.go +++ b/pkg/format/g726.go @@ -15,19 +15,19 @@ type G726 struct { BigEndian bool } -func (f *G726) unmarshal(payloadType uint8, _ string, codec string, _ string, _ map[string]string) error { - f.PayloadTyp = payloadType +func (f *G726) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - if strings.HasPrefix(codec, "aal2-") { + if strings.HasPrefix(ctx.codec, "aal2-") { f.BigEndian = true } switch { - case strings.HasSuffix(codec, "-16"): + case strings.HasSuffix(ctx.codec, "-16"): f.BitRate = 16 - case strings.HasSuffix(codec, "-24"): + case strings.HasSuffix(ctx.codec, "-24"): f.BitRate = 24 - case strings.HasSuffix(codec, "-32"): + case strings.HasSuffix(ctx.codec, "-32"): f.BitRate = 32 default: f.BitRate = 40 diff --git a/pkg/format/generic.go b/pkg/format/generic.go index fe827550..270d973a 100644 --- a/pkg/format/generic.go +++ b/pkg/format/generic.go @@ -8,7 +8,7 @@ import ( "github.com/pion/rtp" ) -func findClockRate(payloadType uint8, rtpMap string) (int, error) { +func findClockRate(payloadType uint8, rtpMap string, isApplication bool) (int, error) { // get clock rate from payload type // https://en.wikipedia.org/wiki/RTP_payload_formats switch payloadType { @@ -34,21 +34,23 @@ func findClockRate(payloadType uint8, rtpMap string) (int, error) { // get clock rate from rtpmap // https://tools.ietf.org/html/rfc4566 // a=rtpmap: / [/] - if rtpMap == "" { - return 0, fmt.Errorf("attribute 'rtpmap' not found") + if rtpMap != "" { + if tmp := strings.Split(rtpMap, "/"); len(tmp) >= 2 { + v, err := strconv.ParseUint(tmp[1], 10, 31) + if err != nil { + return 0, err + } + return int(v), nil + } } - tmp := strings.Split(rtpMap, "/") - if len(tmp) != 2 && len(tmp) != 3 { - return 0, fmt.Errorf("invalid rtpmap (%v)", rtpMap) + // application format without clock rate. + // do not throw an error, but return zero, that disables RTCP sender and receiver reports. + if isApplication || rtpMap != "" { + return 0, nil } - v, err := strconv.ParseUint(tmp[1], 10, 31) - if err != nil { - return 0, err - } - - return int(v), nil + return 0, fmt.Errorf("clock rate not found") } // Generic is a generic RTP format. @@ -63,16 +65,19 @@ type Generic struct { // Init computes the clock rate of the format. It is mandatory to call it. func (f *Generic) Init() error { - f.ClockRat, _ = findClockRate(f.PayloadTyp, f.RTPMa) - return nil + var err error + f.ClockRat, err = findClockRate(f.PayloadTyp, f.RTPMa, true) + return err } -func (f *Generic) unmarshal(payloadType uint8, _ string, _ string, rtpmap string, fmtp map[string]string) error { - f.PayloadTyp = payloadType - f.RTPMa = rtpmap - f.FMT = fmtp +func (f *Generic) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType + f.RTPMa = ctx.rtpMap + f.FMT = ctx.fmtp - return f.Init() + var err error + f.ClockRat, err = findClockRate(f.PayloadTyp, f.RTPMa, ctx.mediaType == "application") + return err } // Codec implements Format. diff --git a/pkg/format/h264.go b/pkg/format/h264.go index d59d3d2a..6fc8e98d 100644 --- a/pkg/format/h264.go +++ b/pkg/format/h264.go @@ -25,10 +25,10 @@ type H264 struct { mutex sync.RWMutex } -func (f *H264) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *H264) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "sprop-parameter-sets": tmp := strings.Split(val, ",") diff --git a/pkg/format/h265.go b/pkg/format/h265.go index 0d3232a9..44cfb89c 100644 --- a/pkg/format/h265.go +++ b/pkg/format/h265.go @@ -24,36 +24,36 @@ type H265 struct { mutex sync.RWMutex } -func (f *H265) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *H265) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "sprop-vps": var err error f.VPS, err = base64.StdEncoding.DecodeString(val) if err != nil { - return fmt.Errorf("invalid sprop-vps (%v)", fmtp) + return fmt.Errorf("invalid sprop-vps (%v)", ctx.fmtp) } case "sprop-sps": var err error f.SPS, err = base64.StdEncoding.DecodeString(val) if err != nil { - return fmt.Errorf("invalid sprop-sps (%v)", fmtp) + return fmt.Errorf("invalid sprop-sps (%v)", ctx.fmtp) } case "sprop-pps": var err error f.PPS, err = base64.StdEncoding.DecodeString(val) if err != nil { - return fmt.Errorf("invalid sprop-pps (%v)", fmtp) + return fmt.Errorf("invalid sprop-pps (%v)", ctx.fmtp) } case "sprop-max-don-diff": tmp, err := strconv.ParseUint(val, 10, 31) if err != nil { - return fmt.Errorf("invalid sprop-max-don-diff (%v)", fmtp) + return fmt.Errorf("invalid sprop-max-don-diff (%v)", ctx.fmtp) } f.MaxDONDiff = int(tmp) } diff --git a/pkg/format/lpcm.go b/pkg/format/lpcm.go index 57639c54..c461cb8a 100644 --- a/pkg/format/lpcm.go +++ b/pkg/format/lpcm.go @@ -18,10 +18,10 @@ type LPCM struct { ChannelCount int } -func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, _ string, _ map[string]string) error { - f.PayloadTyp = payloadType +func (f *LPCM) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - switch codec { + switch ctx.codec { case "l8": f.BitDepth = 8 @@ -32,7 +32,7 @@ func (f *LPCM) unmarshal(payloadType uint8, clock string, codec string, _ string f.BitDepth = 24 } - tmp := strings.SplitN(clock, "/", 2) + tmp := strings.SplitN(ctx.clock, "/", 2) tmp1, err := strconv.ParseUint(tmp[0], 10, 31) if err != nil { diff --git a/pkg/format/mjpeg.go b/pkg/format/mjpeg.go index 1b344465..1097f2f8 100644 --- a/pkg/format/mjpeg.go +++ b/pkg/format/mjpeg.go @@ -10,7 +10,7 @@ import ( // Specification: https://datatracker.ietf.org/doc/html/rfc2435 type MJPEG struct{} -func (f *MJPEG) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error { +func (f *MJPEG) unmarshal(_ *unmarshalContext) error { return nil } diff --git a/pkg/format/mpeg1_audio.go b/pkg/format/mpeg1_audio.go index ec57a45c..5daacca5 100644 --- a/pkg/format/mpeg1_audio.go +++ b/pkg/format/mpeg1_audio.go @@ -10,7 +10,7 @@ import ( // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEG1Audio struct{} -func (f *MPEG1Audio) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error { +func (f *MPEG1Audio) unmarshal(_ *unmarshalContext) error { return nil } diff --git a/pkg/format/mpeg1_video.go b/pkg/format/mpeg1_video.go index ee9ac0e5..54c6a1af 100644 --- a/pkg/format/mpeg1_video.go +++ b/pkg/format/mpeg1_video.go @@ -8,7 +8,7 @@ import ( // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEG1Video struct{} -func (f *MPEG1Video) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error { +func (f *MPEG1Video) unmarshal(_ *unmarshalContext) error { return nil } diff --git a/pkg/format/mpeg4_audio_generic.go b/pkg/format/mpeg4_audio_generic.go index e286102b..421022d9 100644 --- a/pkg/format/mpeg4_audio_generic.go +++ b/pkg/format/mpeg4_audio_generic.go @@ -26,13 +26,10 @@ type MPEG4AudioGeneric struct { IndexDeltaLength int } -func (f *MPEG4AudioGeneric) unmarshal( - payloadType uint8, _ string, _ string, - _ string, fmtp map[string]string, -) error { - f.PayloadTyp = payloadType +func (f *MPEG4AudioGeneric) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "streamtype": if val != "5" { // AudioStream in ISO 14496-1 diff --git a/pkg/format/mpeg4_audio_latm.go b/pkg/format/mpeg4_audio_latm.go index e48b6126..7ddce528 100644 --- a/pkg/format/mpeg4_audio_latm.go +++ b/pkg/format/mpeg4_audio_latm.go @@ -22,17 +22,14 @@ type MPEG4AudioLATM struct { SBREnabled *bool } -func (f *MPEG4AudioLATM) unmarshal( - payloadType uint8, _ string, _ string, - _ string, fmtp map[string]string, -) error { - f.PayloadTyp = payloadType +func (f *MPEG4AudioLATM) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType // default value set by specification f.ProfileLevelID = 30 f.CPresent = true - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "profile-level-id": tmp, err := strconv.ParseUint(val, 10, 31) diff --git a/pkg/format/mpeg4_video_es.go b/pkg/format/mpeg4_video_es.go index 8cd477ea..2a09cd57 100644 --- a/pkg/format/mpeg4_video_es.go +++ b/pkg/format/mpeg4_video_es.go @@ -22,14 +22,11 @@ type MPEG4VideoES struct { Config []byte } -func (f *MPEG4VideoES) unmarshal( - payloadType uint8, _ string, _ string, - _ string, fmtp map[string]string, -) error { - f.PayloadTyp = payloadType - f.ProfileLevelID = 1 // default value defined by specification +func (f *MPEG4VideoES) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType + f.ProfileLevelID = 1 // default value imposed by specification - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "profile-level-id": tmp, err := strconv.ParseUint(val, 10, 31) diff --git a/pkg/format/mpegts.go b/pkg/format/mpegts.go index 124c6573..272446fe 100644 --- a/pkg/format/mpegts.go +++ b/pkg/format/mpegts.go @@ -8,7 +8,7 @@ import ( // Specification: https://datatracker.ietf.org/doc/html/rfc2250 type MPEGTS struct{} -func (f *MPEGTS) unmarshal(_ uint8, _ string, _ string, _ string, _ map[string]string) error { +func (f *MPEGTS) unmarshal(_ *unmarshalContext) error { return nil } diff --git a/pkg/format/opus.go b/pkg/format/opus.go index 659a30c4..0ec2e318 100644 --- a/pkg/format/opus.go +++ b/pkg/format/opus.go @@ -17,12 +17,12 @@ type Opus struct { IsStereo bool } -func (f *Opus) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *Opus) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - tmp := strings.SplitN(clock, "/", 2) + tmp := strings.SplitN(ctx.clock, "/", 2) if len(tmp) != 2 { - return fmt.Errorf("invalid clock (%v)", clock) + return fmt.Errorf("invalid clock (%v)", ctx.clock) } sampleRate, err := strconv.ParseUint(tmp[0], 10, 31) @@ -35,7 +35,7 @@ func (f *Opus) unmarshal(payloadType uint8, clock string, _ string, _ string, fm return fmt.Errorf("invalid channel count: %d", channelCount) } - for key, val := range fmtp { + for key, val := range ctx.fmtp { if key == "sprop-stereo" { f.IsStereo = (val == "1") } diff --git a/pkg/format/speex.go b/pkg/format/speex.go index c82f55cc..24b6cc04 100644 --- a/pkg/format/speex.go +++ b/pkg/format/speex.go @@ -15,16 +15,16 @@ type Speex struct { VBR *bool } -func (f *Speex) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *Speex) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - sampleRate, err := strconv.ParseUint(clock, 10, 31) + sampleRate, err := strconv.ParseUint(ctx.clock, 10, 31) if err != nil { return err } f.SampleRate = int(sampleRate) - for key, val := range fmtp { + for key, val := range ctx.fmtp { if key == "vbr" { if val != "on" && val != "off" { return fmt.Errorf("invalid vbr value: %v", val) diff --git a/pkg/format/vorbis.go b/pkg/format/vorbis.go index fbfad92d..61fab87b 100644 --- a/pkg/format/vorbis.go +++ b/pkg/format/vorbis.go @@ -18,12 +18,12 @@ type Vorbis struct { Configuration []byte } -func (f *Vorbis) unmarshal(payloadType uint8, clock string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *Vorbis) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - tmp := strings.SplitN(clock, "/", 2) + tmp := strings.SplitN(ctx.clock, "/", 2) if len(tmp) != 2 { - return fmt.Errorf("invalid clock (%v)", clock) + return fmt.Errorf("invalid clock (%v)", ctx.clock) } sampleRate, err := strconv.ParseUint(tmp[0], 10, 31) @@ -38,7 +38,7 @@ func (f *Vorbis) unmarshal(payloadType uint8, clock string, _ string, _ string, } f.ChannelCount = int(channelCount) - for key, val := range fmtp { + for key, val := range ctx.fmtp { if key == "configuration" { conf, err := base64.StdEncoding.DecodeString(val) if err != nil { diff --git a/pkg/format/vp8.go b/pkg/format/vp8.go index 13316f30..c699445d 100644 --- a/pkg/format/vp8.go +++ b/pkg/format/vp8.go @@ -17,10 +17,10 @@ type VP8 struct { MaxFS *int } -func (f *VP8) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *VP8) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "max-fr": n, err := strconv.ParseUint(val, 10, 31) diff --git a/pkg/format/vp9.go b/pkg/format/vp9.go index 161e076a..9b6f7605 100644 --- a/pkg/format/vp9.go +++ b/pkg/format/vp9.go @@ -18,10 +18,10 @@ type VP9 struct { ProfileID *int } -func (f *VP9) unmarshal(payloadType uint8, _ string, _ string, _ string, fmtp map[string]string) error { - f.PayloadTyp = payloadType +func (f *VP9) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType - for key, val := range fmtp { + for key, val := range ctx.fmtp { switch key { case "max-fr": n, err := strconv.ParseUint(val, 10, 31)