diff --git a/pkg/formats/av1.go b/pkg/formats/av1.go index 3ba15730..f554c97d 100644 --- a/pkg/formats/av1.go +++ b/pkg/formats/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/formats/format.go b/pkg/formats/format.go index 688fa94b..3d89cc05 100644 --- a/pkg/formats/format.go +++ b/pkg/formats/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 @@ -49,81 +58,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 == 26: + return &MJPEG{} + + case payloadType == 32: + return &MPEG1Video{} - case payloadType == 32: - return &MPEG1Video{} + case payloadType == 33: + return &MPEGTS{} - case payloadType == 33: - return &MPEGTS{} + case codec == "mp4v-es" && clock == "90000": + return &MPEG4Video{} - case codec == "mp4v-es" && clock == "90000": - return &MPEG4Video{} + case codec == "h264" && clock == "90000": + return &H264{} - case codec == "h264" && clock == "90000": - return &H264{} + case codec == "h265" && clock == "90000": + return &H265{} - case codec == "h265" && clock == "90000": - return &H265{} + case codec == "vp8" && clock == "90000": + return &VP8{} - case codec == "vp8" && clock == "90000": - return &VP8{} + case codec == "vp9" && clock == "90000": + return &VP9{} - case codec == "vp9" && clock == "90000": - return &VP9{} + case codec == "av1" && clock == "90000": + return &AV1{} - case codec == "av1" && clock == "90000": - return &AV1{} - } + // audio - case mediaType == "audio": - switch { - case payloadType == 0, payloadType == 8: - return &G711{} + case payloadType == 0, payloadType == 8: + return &G711{} - case payloadType == 9: - return &G722{} + case payloadType == 9: + return &G722{} - 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 == "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 == 14: - return &MPEG1Audio{} + case payloadType == 14: + return &MPEG1Audio{} - case codec == "l8", codec == "l16", codec == "l24": - return &LPCM{} + case codec == "l8", codec == "l16", codec == "l24": + return &LPCM{} - case codec == "mpeg4-generic": - return &MPEG4AudioGeneric{} + case codec == "mpeg4-generic": + return &MPEG4AudioGeneric{} - case codec == "mp4a-latm": - return &MPEG4AudioLATM{} + case codec == "mp4a-latm": + return &MPEG4AudioLATM{} - case codec == "speex": - return &Speex{} + case codec == "speex": + return &Speex{} - case codec == "vorbis": - return &Vorbis{} + case codec == "vorbis": + return &Vorbis{} - case codec == "opus": - return &Opus{} - } + 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/formats/format_test.go b/pkg/formats/format_test.go index 04aecb8e..93322504 100644 --- a/pkg/formats/format_test.go +++ b/pkg/formats/format_test.go @@ -912,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/formats/g711.go b/pkg/formats/g711.go index 39dc9ee5..9ae7a82a 100644 --- a/pkg/formats/g711.go +++ b/pkg/formats/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/formats/g722.go b/pkg/formats/g722.go index 7a320ffd..5e731c22 100644 --- a/pkg/formats/g722.go +++ b/pkg/formats/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/formats/g726.go b/pkg/formats/g726.go index a15fb9f8..a03c88d0 100644 --- a/pkg/formats/g726.go +++ b/pkg/formats/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/formats/generic.go b/pkg/formats/generic.go index 0173fd36..bca95d85 100644 --- a/pkg/formats/generic.go +++ b/pkg/formats/generic.go @@ -1,13 +1,14 @@ package formats import ( + "fmt" "strconv" "strings" "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 { @@ -43,9 +44,13 @@ func findClockRate(payloadType uint8, rtpMap string) (int, error) { } } - // no clock rate was found. + // application format without clock rate. // do not throw an error, but return zero, that disables RTCP sender and receiver reports. - return 0, nil + if isApplication || rtpMap != "" { + return 0, nil + } + + return 0, fmt.Errorf("clock rate not found") } // Generic is a generic RTP format. @@ -61,16 +66,18 @@ type Generic struct { // Init computes the clock rate of the format. It is mandatory to call it. func (f *Generic) Init() error { var err error - f.ClockRat, err = findClockRate(f.PayloadTyp, f.RTPMa) + 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/formats/h264.go b/pkg/formats/h264.go index 1862d2a8..7b933ef3 100644 --- a/pkg/formats/h264.go +++ b/pkg/formats/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/formats/h265.go b/pkg/formats/h265.go index 03dac11f..102e174b 100644 --- a/pkg/formats/h265.go +++ b/pkg/formats/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/formats/lpcm.go b/pkg/formats/lpcm.go index c1dbbdc4..b3e95906 100644 --- a/pkg/formats/lpcm.go +++ b/pkg/formats/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/formats/mjpeg.go b/pkg/formats/mjpeg.go index a14d6148..19ab3f3e 100644 --- a/pkg/formats/mjpeg.go +++ b/pkg/formats/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/formats/mpeg1_audio.go b/pkg/formats/mpeg1_audio.go index 55a9fcb1..ec91305a 100644 --- a/pkg/formats/mpeg1_audio.go +++ b/pkg/formats/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/formats/mpeg1_video.go b/pkg/formats/mpeg1_video.go index 2c43c9cc..f795478a 100644 --- a/pkg/formats/mpeg1_video.go +++ b/pkg/formats/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/formats/mpeg4_audio_generic.go b/pkg/formats/mpeg4_audio_generic.go index 7c3d65f2..2132b528 100644 --- a/pkg/formats/mpeg4_audio_generic.go +++ b/pkg/formats/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/formats/mpeg4_audio_latm.go b/pkg/formats/mpeg4_audio_latm.go index 47428e1e..4b9c5021 100644 --- a/pkg/formats/mpeg4_audio_latm.go +++ b/pkg/formats/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/formats/mpeg4_video_es.go b/pkg/formats/mpeg4_video_es.go index 6982ba60..9346ec86 100644 --- a/pkg/formats/mpeg4_video_es.go +++ b/pkg/formats/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 - - for key, val := range fmtp { +func (f *MPEG4VideoES) unmarshal(ctx *unmarshalContext) error { + f.PayloadTyp = ctx.payloadType + f.ProfileLevelID = 1 // default value imposed by specification + + for key, val := range ctx.fmtp { switch key { case "profile-level-id": tmp, err := strconv.ParseUint(val, 10, 31) diff --git a/pkg/formats/mpegts.go b/pkg/formats/mpegts.go index b68c48c0..b2d2146e 100644 --- a/pkg/formats/mpegts.go +++ b/pkg/formats/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/formats/opus.go b/pkg/formats/opus.go index 4f898b2a..54fbcd75 100644 --- a/pkg/formats/opus.go +++ b/pkg/formats/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/formats/speex.go b/pkg/formats/speex.go index 5484df1a..75b486cb 100644 --- a/pkg/formats/speex.go +++ b/pkg/formats/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/formats/vorbis.go b/pkg/formats/vorbis.go index 7e05295b..3b0ea105 100644 --- a/pkg/formats/vorbis.go +++ b/pkg/formats/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/formats/vp8.go b/pkg/formats/vp8.go index cf46cf24..75458c4e 100644 --- a/pkg/formats/vp8.go +++ b/pkg/formats/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/formats/vp9.go b/pkg/formats/vp9.go index 53c4de23..073aab9c 100644 --- a/pkg/formats/vp9.go +++ b/pkg/formats/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)