diff --git a/.golangci.yml b/.golangci.yml index a3235be..50211be 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -25,17 +25,32 @@ linters-settings: - ^os.Exit$ - ^panic$ - ^print(ln)?$ + varnamelen: + max-distance: 12 + min-name-length: 2 + ignore-type-assert-ok: true + ignore-map-index-ok: true + ignore-chan-recv-ok: true + ignore-decls: + - i int + - n int + - w io.Writer + - r io.Reader + - b []byte linters: enable: - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers - bidichk # Checks for dangerous unicode character sequences - bodyclose # checks whether HTTP response body is closed successfully + - containedctx # containedctx is a linter that detects struct contained context.Context field - contextcheck # check the function whether use a non-inherited context + - cyclop # checks function and package cyclomatic complexity - decorder # check declaration order and count of types, constants, variables and functions - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f()) - dupl # Tool for code clone detection - durationcheck # check for two durations multiplied together + - err113 # Golang linter to check the errors handling expressions - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases - errchkjson # Checks types passed to the json encoding functions. Reports unsupported types and optionally reports occations, where the check for the returned error can be omitted. - errname # Checks that sentinel errors are prefixed with the `Err` and error types are suffixed with the `Error`. @@ -44,20 +59,20 @@ linters: - exportloopref # checks for pointers to enclosing loop variables - forbidigo # Forbids identifiers - forcetypeassert # finds forced type assertions + - funlen # Tool for detection of long functions - gci # Gci control golang package import order and make it always deterministic. - gochecknoglobals # Checks that no globals are present in Go code - - gochecknoinits # Checks that no init functions are present in Go code - gocognit # Computes and checks the cognitive complexity of functions - goconst # Finds repeated strings that could be replaced by a constant - gocritic # The most opinionated Go source code linter + - gocyclo # Computes and checks the cyclomatic complexity of functions + - godot # Check if comments end in a period - godox # Tool for detection of FIXME, TODO and other comment keywords - - err113 # Golang linter to check the errors handling expressions - gofmt # Gofmt checks whether code was gofmt-ed. By default this tool runs with -s option to check for code simplification - gofumpt # Gofumpt checks whether code was gofumpt-ed. - goheader # Checks is file header matches to pattern - goimports # Goimports does everything that gofmt does. Additionally it checks unused imports - gomoddirectives # Manage the use of 'replace', 'retract', and 'excludes' directives in go.mod. - - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. - goprintffuncname # Checks that printf-like functions are named with `f` at the end - gosec # Inspects source code for security problems - gosimple # Linter for Go source code that specializes in simplifying a code @@ -65,9 +80,15 @@ linters: - grouper # An analyzer to analyze expression groups. - importas # Enforces consistent import aliases - ineffassign # Detects when assignments to existing variables are not used + - lll # Reports long lines + - maintidx # maintidx measures the maintainability index of each function. + - makezero # Finds slice declarations with non-zero initial length - misspell # Finds commonly misspelled English words in comments + - nakedret # Finds naked returns in functions greater than a specified function length + - nestif # Reports deeply nested if statements - nilerr # Finds the code that returns nil even if it checks that the error is not nil. - nilnil # Checks that there is no simultaneous return of `nil` error and an invalid value. + - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity - noctx # noctx finds sending http request without context.Context - predeclared # find code that shadows one of Go's predeclared identifiers - revive # golint replacement, finds style mistakes @@ -75,28 +96,21 @@ linters: - stylecheck # Stylecheck is a replacement for golint - tagliatelle # Checks the struct tags. - tenv # tenv is analyzer that detects using os.Setenv instead of t.Setenv since Go1.17 - - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes + - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - typecheck # Like the front-end of a Go compiler, parses and type-checks Go code - unconvert # Remove unnecessary type conversions - unparam # Reports unused function parameters - unused # Checks Go code for unused constants, variables, functions and types + - varnamelen # checks that the length of a variable's name matches its scope - wastedassign # wastedassign finds wasted assignment statements - whitespace # Tool for detection of leading and trailing whitespace disable: - depguard # Go linter that checks if package imports are in a list of acceptable packages - - containedctx # containedctx is a linter that detects struct contained context.Context field - - cyclop # checks function and package cyclomatic complexity - - funlen # Tool for detection of long functions - - gocyclo # Computes and checks the cyclomatic complexity of functions - - godot # Check if comments end in a period - - gomnd # An analyzer to detect magic numbers. + - gochecknoinits # Checks that no init functions are present in Go code + - gomodguard # Allow and block list linter for direct Go module dependencies. This is different from depguard where there are different block types for example version constraints and module recommendations. + - interfacebloat # A linter that checks length of interface. - ireturn # Accept Interfaces, Return Concrete Types - - lll # Reports long lines - - maintidx # maintidx measures the maintainability index of each function. - - makezero # Finds slice declarations with non-zero initial length - - nakedret # Finds naked returns in functions greater than a specified function length - - nestif # Reports deeply nested if statements - - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity + - mnd # An analyzer to detect magic numbers - nolintlint # Reports ill-formed or insufficient nolint directives - paralleltest # paralleltest detects missing usage of t.Parallel() method in your Go test - prealloc # Finds slice declarations that could potentially be preallocated @@ -104,8 +118,7 @@ linters: - rowserrcheck # checks whether Err of rows is checked successfully - sqlclosecheck # Checks that sql.Rows and sql.Stmt are closed. - testpackage # linter that makes you use a separate _test package - - thelper # thelper detects golang test helpers without t.Helper() call and checks the consistency of test helpers - - varnamelen # checks that the length of a variable's name matches its scope + - tparallel # tparallel detects inappropriate usage of t.Parallel() method in your Go test codes - wrapcheck # Checks that errors returned from external packages are wrapped - wsl # Whitespace Linter - Forces you to use empty lines! diff --git a/abscapturetimeextension.go b/abscapturetimeextension.go index 5e96cff..68b43ca 100644 --- a/abscapturetimeextension.go +++ b/abscapturetimeextension.go @@ -13,7 +13,7 @@ const ( absCaptureTimeExtendedExtensionSize = 16 ) -// AbsCaptureTimeExtension is a extension payload format in +// AbsCaptureTimeExtension is a extension payload format in. // http://www.webrtc.org/experiments/rtp-hdrext/abs-capture-time // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -24,6 +24,7 @@ const ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ... (56-63) | // +-+-+-+-+-+-+-+-+ +// . type AbsCaptureTimeExtension struct { Timestamp uint64 EstimatedCaptureClockOffset *int64 @@ -34,11 +35,13 @@ func (t AbsCaptureTimeExtension) Marshal() ([]byte, error) { if t.EstimatedCaptureClockOffset != nil { buf := make([]byte, 16) binary.BigEndian.PutUint64(buf[0:8], t.Timestamp) - binary.BigEndian.PutUint64(buf[8:16], uint64(*t.EstimatedCaptureClockOffset)) + binary.BigEndian.PutUint64(buf[8:16], uint64(*t.EstimatedCaptureClockOffset)) // nolint: gosec // G115 + return buf, nil } buf := make([]byte, 8) binary.BigEndian.PutUint64(buf[0:8], t.Timestamp) + return buf, nil } @@ -49,9 +52,10 @@ func (t *AbsCaptureTimeExtension) Unmarshal(rawData []byte) error { } t.Timestamp = binary.BigEndian.Uint64(rawData[0:8]) if len(rawData) >= absCaptureTimeExtendedExtensionSize { - offset := int64(binary.BigEndian.Uint64(rawData[8:16])) + offset := int64(binary.BigEndian.Uint64(rawData[8:16])) // nolint: gosec // G115 false positive t.EstimatedCaptureClockOffset = &offset } + return nil } @@ -75,6 +79,7 @@ func (t AbsCaptureTimeExtension) EstimatedCaptureClockOffsetDuration() *time.Dur if negative { duration = -duration } + return &duration } @@ -86,7 +91,10 @@ func NewAbsCaptureTimeExtension(captureTime time.Time) *AbsCaptureTimeExtension } // NewAbsCaptureTimeExtensionWithCaptureClockOffset makes new AbsCaptureTimeExtension from time.Time and a clock offset. -func NewAbsCaptureTimeExtensionWithCaptureClockOffset(captureTime time.Time, captureClockOffset time.Duration) *AbsCaptureTimeExtension { +func NewAbsCaptureTimeExtensionWithCaptureClockOffset( + captureTime time.Time, + captureClockOffset time.Duration, +) *AbsCaptureTimeExtension { ns := captureClockOffset.Nanoseconds() negative := false if ns < 0 { @@ -99,6 +107,7 @@ func NewAbsCaptureTimeExtensionWithCaptureClockOffset(captureTime time.Time, cap if negative { offset = -offset } + return &AbsCaptureTimeExtension{ Timestamp: toNtpTime(captureTime), EstimatedCaptureClockOffset: &offset, diff --git a/abscapturetimeextension_test.go b/abscapturetimeextension_test.go index 038e677..395e02b 100644 --- a/abscapturetimeextension_test.go +++ b/abscapturetimeextension_test.go @@ -8,7 +8,7 @@ import ( "time" ) -func TestAbsCaptureTimeExtension_Roundtrip(t *testing.T) { +func TestAbsCaptureTimeExtension_Roundtrip(t *testing.T) { // nolint: funlen,cyclop t.Run("positive captureClockOffset", func(t *testing.T) { t0 := time.Now() e1 := NewAbsCaptureTimeExtension(t0) diff --git a/abssendtimeextension.go b/abssendtimeextension.go index fff38e9..d66e47c 100644 --- a/abssendtimeextension.go +++ b/abssendtimeextension.go @@ -32,6 +32,7 @@ func (t *AbsSendTimeExtension) Unmarshal(rawData []byte) error { return errTooSmall } t.Timestamp = uint64(rawData[0])<<16 | uint64(rawData[1])<<8 | uint64(rawData[2]) + return nil } @@ -58,7 +59,7 @@ func NewAbsSendTimeExtension(sendTime time.Time) *AbsSendTimeExtension { func toNtpTime(t time.Time) uint64 { var s uint64 var f uint64 - u := uint64(t.UnixNano()) + u := uint64(t.UnixNano()) // nolint: gosec // G115 false positive s = u / 1e9 s += 0x83AA7E80 // offset in seconds between unix epoch and ntp epoch f = u % 1e9 @@ -77,5 +78,5 @@ func toTime(t uint64) time.Time { s -= 0x83AA7E80 u := s*1e9 + f - return time.Unix(0, int64(u)) + return time.Unix(0, int64(u)) // nolint: gosec // G115 false positive } diff --git a/audiolevelextension.go b/audiolevelextension.go index f180c8d..cc2e652 100644 --- a/audiolevelextension.go +++ b/audiolevelextension.go @@ -8,7 +8,7 @@ import ( ) const ( - // audioLevelExtensionSize One byte header size + // audioLevelExtensionSize One byte header size. audioLevelExtensionSize = 1 ) @@ -33,12 +33,14 @@ var errAudioLevelOverflow = errors.New("audio level overflow") // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=1 |V| level | 0 (pad) | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// +//nolint:lll type AudioLevelExtension struct { Level uint8 Voice bool } -// Marshal serializes the members to buffer +// Marshal serializes the members to buffer. func (a AudioLevelExtension) Marshal() ([]byte, error) { if a.Level > 127 { return nil, errAudioLevelOverflow @@ -49,15 +51,17 @@ func (a AudioLevelExtension) Marshal() ([]byte, error) { } buf := make([]byte, audioLevelExtensionSize) buf[0] = voice | a.Level + return buf, nil } -// Unmarshal parses the passed byte slice and stores the result in the members +// Unmarshal parses the passed byte slice and stores the result in the members. func (a *AudioLevelExtension) Unmarshal(rawData []byte) error { if len(rawData) < audioLevelExtensionSize { return errTooSmall } a.Level = rawData[0] & 0x7F a.Voice = rawData[0]&0x80 != 0 + return nil } diff --git a/codecs/av1/frame/av1.go b/codecs/av1/frame/av1.go index 1e001a3..99ed29c 100644 --- a/codecs/av1/frame/av1.go +++ b/codecs/av1/frame/av1.go @@ -26,10 +26,11 @@ func (f *AV1) pushOBUElement(isFirstOBUFragment *bool, obuElement []byte, obuLis obuElement = append(f.obuBuffer, obuElement...) f.obuBuffer = nil } + return append(obuList, obuElement) } -// ReadFrames processes the codecs.AV1Packet and returns fully constructed frames +// ReadFrames processes the codecs.AV1Packet and returns fully constructed frames. func (f *AV1) ReadFrames(pkt *codecs.AV1Packet) ([][]byte, error) { OBUs := [][]byte{} isFirstOBUFragment := pkt.Z @@ -43,5 +44,6 @@ func (f *AV1) ReadFrames(pkt *codecs.AV1Packet) ([][]byte, error) { f.obuBuffer = append(f.obuBuffer, append([]byte{}, OBUs[len(OBUs)-1]...)...) OBUs = OBUs[:len(OBUs)-1] } + return OBUs, nil } diff --git a/codecs/av1/frame/av1_test.go b/codecs/av1/frame/av1_test.go index aa6c73c..2e6c2b4 100644 --- a/codecs/av1/frame/av1_test.go +++ b/codecs/av1/frame/av1_test.go @@ -12,34 +12,34 @@ import ( // First is Fragment (and no buffer) // Self contained OBU -// OBU spread across 3 packets +// OBU spread across 3 packets. func TestAV1_ReadFrames(t *testing.T) { // First is Fragment of OBU, but no OBU Elements is cached - f := &AV1{} - frames, err := f.ReadFrames(&codecs.AV1Packet{Z: true, OBUElements: [][]byte{{0x01}}}) + fragm := &AV1{} + frames, err := fragm.ReadFrames(&codecs.AV1Packet{Z: true, OBUElements: [][]byte{{0x01}}}) if err != nil { t.Fatal(err) } else if !reflect.DeepEqual(frames, [][]byte{}) { t.Fatalf("No frames should be generated, %v", frames) } - f = &AV1{} - frames, err = f.ReadFrames(&codecs.AV1Packet{OBUElements: [][]byte{{0x01}}}) + fragm = &AV1{} + frames, err = fragm.ReadFrames(&codecs.AV1Packet{OBUElements: [][]byte{{0x01}}}) if err != nil { t.Fatal(err) } else if !reflect.DeepEqual(frames, [][]byte{{0x01}}) { t.Fatalf("One frame should be generated, %v", frames) } - f = &AV1{} - frames, err = f.ReadFrames(&codecs.AV1Packet{Y: true, OBUElements: [][]byte{{0x00}}}) + fragm = &AV1{} + frames, err = fragm.ReadFrames(&codecs.AV1Packet{Y: true, OBUElements: [][]byte{{0x00}}}) if err != nil { t.Fatal(err) } else if !reflect.DeepEqual(frames, [][]byte{}) { t.Fatalf("No frames should be generated, %v", frames) } - frames, err = f.ReadFrames(&codecs.AV1Packet{Z: true, OBUElements: [][]byte{{0x01}}}) + frames, err = fragm.ReadFrames(&codecs.AV1Packet{Z: true, OBUElements: [][]byte{{0x01}}}) if err != nil { t.Fatal(err) } else if !reflect.DeepEqual(frames, [][]byte{{0x00, 0x01}}) { @@ -47,24 +47,33 @@ func TestAV1_ReadFrames(t *testing.T) { } } -// Marshal some AV1 Frames to RTP, assert that AV1 can get them back in the original format +// Marshal some AV1 Frames to RTP, assert that AV1 can get them back in the original format. func TestAV1_ReadFrames_E2E(t *testing.T) { const mtu = 1500 frames := [][]byte{ {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, {0x00, 0x01}, - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}, + { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, + }, {0x00, 0x01}, } frames = append(frames, []byte{}) for i := 0; i <= 5; i++ { - frames[len(frames)-1] = append(frames[len(frames)-1], []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}...) + frames[len(frames)-1] = append( + frames[len(frames)-1], + []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}..., + ) } frames = append(frames, []byte{}) for i := 0; i <= 500; i++ { - frames[len(frames)-1] = append(frames[len(frames)-1], []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}...) + frames[len(frames)-1] = append( + frames[len(frames)-1], + []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A}..., + ) } payloader := &codecs.AV1Payloader{} diff --git a/codecs/av1/obu/leb128.go b/codecs/av1/obu/leb128.go index f5fcbf6..56b9ff0 100644 --- a/codecs/av1/obu/leb128.go +++ b/codecs/av1/obu/leb128.go @@ -11,10 +11,10 @@ const ( msbBitmask = uint(0b10000000) ) -// ErrFailedToReadLEB128 indicates that a buffer ended before a LEB128 value could be successfully read +// ErrFailedToReadLEB128 indicates that a buffer ended before a LEB128 value could be successfully read. var ErrFailedToReadLEB128 = errors.New("payload ended before LEB128 was finished") -// EncodeLEB128 encodes a uint as LEB128 +// EncodeLEB128 encodes a uint as LEB128. func EncodeLEB128(in uint) (out uint) { for { // Copy seven bits from in and discard @@ -50,7 +50,7 @@ func decodeLEB128(in uint) (out uint) { // ReadLeb128 scans an buffer and decodes a Leb128 value. // If the end of the buffer is reached and all MSB are set -// an error is returned +// an error is returned. func ReadLeb128(in []byte) (uint, uint, error) { var encodedLength uint @@ -58,7 +58,7 @@ func ReadLeb128(in []byte) (uint, uint, error) { encodedLength |= uint(in[i]) if in[i]&byte(msbBitmask) == 0 { - return decodeLEB128(encodedLength), uint(i + 1), nil + return decodeLEB128(encodedLength), uint(i + 1), nil // nolint: gosec // G115 } // Make more room for next read diff --git a/codecs/av1/obu/leb128_test.go b/codecs/av1/obu/leb128_test.go index 2b2336a..5464649 100644 --- a/codecs/av1/obu/leb128_test.go +++ b/codecs/av1/obu/leb128_test.go @@ -61,6 +61,8 @@ func TestWriteToLeb128(t *testing.T) { } runTest := func(t *testing.T, v testVector) { + t.Helper() + b := WriteToLeb128(v.value) if v.leb128 != hex.EncodeToString(b) { t.Errorf("Expected %s, got %s", v.leb128, hex.EncodeToString(b)) diff --git a/codecs/av1_packet.go b/codecs/av1_packet.go index 84c6c99..a9c69bd 100644 --- a/codecs/av1_packet.go +++ b/codecs/av1_packet.go @@ -30,13 +30,13 @@ const ( leb128Size = 1 ) -// AV1Payloader payloads AV1 packets +// AV1Payloader payloads AV1 packets. type AV1Payloader struct { sequenceHeader []byte } -// Payload fragments a AV1 packet across one or more byte arrays -// See AV1Packet for description of AV1 Payload Header +// Payload fragments a AV1 packet across one or more byte arrays. +// See AV1Packet for description of AV1 Payload Header. func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) { payloadDataIndex := 0 payloadDataRemaining := len(payload) @@ -50,7 +50,8 @@ func (p *AV1Payloader) Payload(mtu uint16, payload []byte) (payloads [][]byte) { frameType := (payload[0] & obuFrameTypeMask) >> obuFrameTypeBitshift if frameType == obuFameTypeSequenceHeader { p.sequenceHeader = payload - return + + return payloads } for payloadDataRemaining > 0 { @@ -138,7 +139,7 @@ type AV1Packet struct { videoDepacketizer } -// Unmarshal parses the passed byte slice and stores the result in the AV1Packet this method is called upon +// Unmarshal parses the passed byte slice and stores the result in the AV1Packet this method is called upon. func (p *AV1Packet) Unmarshal(payload []byte) ([]byte, error) { if payload == nil { return nil, errNilPacket diff --git a/codecs/av1_packet_test.go b/codecs/av1_packet_test.go index 7df5f55..bbe6a8f 100644 --- a/codecs/av1_packet_test.go +++ b/codecs/av1_packet_test.go @@ -12,12 +12,12 @@ import ( "github.com/pion/rtp/codecs/av1/obu" ) -func TestAV1_Marshal(t *testing.T) { - p := &AV1Payloader{} +func TestAV1_Marshal(t *testing.T) { // nolint:funlen,cyclop + payloader := &AV1Payloader{} t.Run("Unfragmented OBU", func(t *testing.T) { OBU := []byte{0x00, 0x01, 0x2, 0x3, 0x4, 0x5} - payloads := p.Payload(100, OBU) + payloads := payloader.Payload(100, OBU) if len(payloads) != 1 || len(payloads[0]) != 7 { t.Fatal("Expected one unfragmented Payload") @@ -34,7 +34,7 @@ func TestAV1_Marshal(t *testing.T) { t.Run("Fragmented OBU", func(t *testing.T) { OBU := []byte{0x00, 0x01, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8} - payloads := p.Payload(4, OBU) + payloads := payloader.Payload(4, OBU) if len(payloads) != 3 || len(payloads[0]) != 4 || len(payloads[1]) != 4 || len(payloads[2]) != 4 { t.Fatal("Expected three fragmented Payload") @@ -52,7 +52,9 @@ func TestAV1_Marshal(t *testing.T) { t.Fatal("W and Z bit should be set") } - if !bytes.Equal(OBU[0:3], payloads[0][1:]) || !bytes.Equal(OBU[3:6], payloads[1][1:]) || !bytes.Equal(OBU[6:9], payloads[2][1:]) { + if !bytes.Equal(OBU[0:3], payloads[0][1:]) || + !bytes.Equal(OBU[3:6], payloads[1][1:]) || + !bytes.Equal(OBU[6:9], payloads[2][1:]) { t.Fatal("OBU modified during packetization") } }) @@ -61,12 +63,12 @@ func TestAV1_Marshal(t *testing.T) { sequenceHeaderFrame := []byte{0xb, 0xA, 0xB, 0xC} normalFrame := []byte{0x0, 0x1, 0x2, 0x3} - payloads := p.Payload(100, sequenceHeaderFrame) + payloads := payloader.Payload(100, sequenceHeaderFrame) if len(payloads) != 0 { t.Fatal("Sequence Header was not properly cached") } - payloads = p.Payload(100, normalFrame) + payloads = payloader.Payload(100, normalFrame) if len(payloads) != 1 { t.Fatal("Expected one payload") } @@ -101,7 +103,7 @@ func TestAV1_Unmarshal_Error(t *testing.T) { } } -func TestAV1_Unmarshal(t *testing.T) { +func TestAV1_Unmarshal(t *testing.T) { // nolint: funlen // nolint: dupl av1Payload := []byte{ 0x68, 0x0c, 0x08, 0x00, 0x00, 0x00, 0x2c, diff --git a/codecs/common.go b/codecs/common.go index 5b7dd14..8d7531a 100644 --- a/codecs/common.go +++ b/codecs/common.go @@ -7,10 +7,11 @@ func minInt(a, b int) int { if a < b { return a } + return b } -// audioDepacketizer is a mixin for audio codec depacketizers +// audioDepacketizer is a mixin for audio codec depacketizers. type audioDepacketizer struct{} func (d *audioDepacketizer) IsPartitionTail(_ bool, _ []byte) bool { @@ -21,7 +22,7 @@ func (d *audioDepacketizer) IsPartitionHead(_ []byte) bool { return true } -// videoDepacketizer is a mixin for video codec depacketizers +// videoDepacketizer is a mixin for video codec depacketizers. type videoDepacketizer struct { zeroAllocation bool } diff --git a/codecs/common_test.go b/codecs/common_test.go index 4c1f393..5955c60 100644 --- a/codecs/common_test.go +++ b/codecs/common_test.go @@ -24,7 +24,7 @@ func TestCommon_Min(t *testing.T) { } } -func TestZeroAllocations(t *testing.T) { +func TestZeroAllocations(t *testing.T) { // nolint: funlen, maintidx type unmarshaller interface { Unmarshal(data []byte) ([]byte, error) } diff --git a/codecs/error.go b/codecs/error.go index 2083ef4..60530e9 100644 --- a/codecs/error.go +++ b/codecs/error.go @@ -12,6 +12,8 @@ var ( errTooManySpatialLayers = errors.New("too many spatial layers") errUnhandledNALUType = errors.New("NALU Type is unhandled") - // AV1 Errors - errIsKeyframeAndFragment = errors.New("bits Z and N are set. Not possible to have OBU be tail fragment and be keyframe") + // AV1 Errors. + errIsKeyframeAndFragment = errors.New( + "bits Z and N are set. Not possible to have OBU be tail fragment and be keyframe", + ) ) diff --git a/codecs/g711_packet.go b/codecs/g711_packet.go index 4afda55..7ac268a 100644 --- a/codecs/g711_packet.go +++ b/codecs/g711_packet.go @@ -3,10 +3,10 @@ package codecs -// G711Payloader payloads G711 packets +// G711Payloader payloads G711 packets. type G711Payloader struct{} -// Payload fragments an G711 packet across one or more byte arrays +// Payload fragments an G711 packet across one or more byte arrays. func (p *G711Payloader) Payload(mtu uint16, payload []byte) [][]byte { var out [][]byte if payload == nil || mtu == 0 { @@ -21,5 +21,6 @@ func (p *G711Payloader) Payload(mtu uint16, payload []byte) [][]byte { } o := make([]byte, len(payload)) copy(o, payload) + return append(out, o) } diff --git a/codecs/g711_packet_test.go b/codecs/g711_packet_test.go index 75fa6a8..bde1da3 100644 --- a/codecs/g711_packet_test.go +++ b/codecs/g711_packet_test.go @@ -10,8 +10,8 @@ import ( "testing" ) -func TestG711Payloader(t *testing.T) { - p := G711Payloader{} +func TestG711Payloader(t *testing.T) { // nolint:funlen + payloader := G711Payloader{} const ( testlen = 10000 @@ -30,7 +30,7 @@ func TestG711Payloader(t *testing.T) { copy(samplesIn, samples) // split our samples into payloads - payloads := p.Payload(testmtu, samplesIn) + payloads := payloader.Payload(testmtu, samplesIn) outcnt := int(math.Ceil(float64(testlen) / testmtu)) if len(payloads) != outcnt { @@ -50,25 +50,25 @@ func TestG711Payloader(t *testing.T) { payload := []byte{0x90, 0x90, 0x90} // 0 MTU, small payload - res := p.Payload(0, payload) + res := payloader.Payload(0, payload) if len(res) != 0 { t.Fatal("Generated payload should be empty") } // Positive MTU, small payload - res = p.Payload(1, payload) + res = payloader.Payload(1, payload) if len(res) != len(payload) { t.Fatal("Generated payload should be the same size as original payload size") } // Positive MTU, small payload - res = p.Payload(uint16(len(payload)-1), payload) + res = payloader.Payload(uint16(len(payload)-1), payload) // nolint: gosec // G115 if len(res) != len(payload)-1 { t.Fatal("Generated payload should be the same smaller than original payload size") } // Positive MTU, small payload - res = p.Payload(10, payload) + res = payloader.Payload(10, payload) if len(res) != 1 { t.Fatal("Generated payload should be 1") } diff --git a/codecs/g722_packet.go b/codecs/g722_packet.go index ae6672d..7d586ab 100644 --- a/codecs/g722_packet.go +++ b/codecs/g722_packet.go @@ -3,10 +3,10 @@ package codecs -// G722Payloader payloads G722 packets +// G722Payloader payloads G722 packets. type G722Payloader struct{} -// Payload fragments an G722 packet across one or more byte arrays +// Payload fragments an G722 packet across one or more byte arrays. func (p *G722Payloader) Payload(mtu uint16, payload []byte) [][]byte { var out [][]byte if payload == nil || mtu == 0 { @@ -21,5 +21,6 @@ func (p *G722Payloader) Payload(mtu uint16, payload []byte) [][]byte { } o := make([]byte, len(payload)) copy(o, payload) + return append(out, o) } diff --git a/codecs/g722_packet_test.go b/codecs/g722_packet_test.go index f15f81c..2bfa04c 100644 --- a/codecs/g722_packet_test.go +++ b/codecs/g722_packet_test.go @@ -10,8 +10,8 @@ import ( "testing" ) -func TestG722Payloader(t *testing.T) { - p := G722Payloader{} +func TestG722Payloader(t *testing.T) { // nolint:funlen + payloader := G722Payloader{} const ( testlen = 10000 @@ -30,7 +30,7 @@ func TestG722Payloader(t *testing.T) { copy(samplesIn, samples) // split our samples into payloads - payloads := p.Payload(testmtu, samplesIn) + payloads := payloader.Payload(testmtu, samplesIn) outcnt := int(math.Ceil(float64(testlen) / testmtu)) if len(payloads) != outcnt { @@ -50,25 +50,25 @@ func TestG722Payloader(t *testing.T) { payload := []byte{0x90, 0x90, 0x90} // 0 MTU, small payload - res := p.Payload(0, payload) + res := payloader.Payload(0, payload) if len(res) != 0 { t.Fatal("Generated payload should be empty") } // Positive MTU, small payload - res = p.Payload(1, payload) + res = payloader.Payload(1, payload) if len(res) != len(payload) { t.Fatal("Generated payload should be the same size as original payload size") } // Positive MTU, small payload - res = p.Payload(uint16(len(payload)-1), payload) + res = payloader.Payload(uint16(len(payload)-1), payload) // nolint: gosec // G115 if len(res) != len(payload)-1 { t.Fatal("Generated payload should be the same smaller than original payload size") } // Positive MTU, small payload - res = p.Payload(10, payload) + res = payloader.Payload(10, payload) if len(res) != 1 { t.Fatal("Generated payload should be 1") } diff --git a/codecs/h264_packet.go b/codecs/h264_packet.go index 227cb9d..e97a880 100644 --- a/codecs/h264_packet.go +++ b/codecs/h264_packet.go @@ -9,7 +9,7 @@ import ( "fmt" ) -// H264Payloader payloads H264 packets +// H264Payloader payloads H264 packets. type H264Payloader struct { spsNalu, ppsNalu []byte } @@ -54,6 +54,7 @@ func emitNalus(nals []byte, emit func([]byte)) { } if end == -1 { emit(nals[start:]) + break } @@ -64,8 +65,8 @@ func emitNalus(nals []byte, emit func([]byte)) { } } -// Payload fragments a H264 packet across one or more byte arrays -func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte { +// Payload fragments a H264 packet across one or more byte arrays. +func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte { // nolint:funlen,cyclop var payloads [][]byte if len(payload) == 0 { return payloads @@ -84,17 +85,19 @@ func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte { return case naluType == spsNALUType: p.spsNalu = nalu + return case naluType == ppsNALUType: p.ppsNalu = nalu + return case p.spsNalu != nil && p.ppsNalu != nil: // Pack current NALU with SPS and PPS as STAP-A spsLen := make([]byte, 2) - binary.BigEndian.PutUint16(spsLen, uint16(len(p.spsNalu))) + binary.BigEndian.PutUint16(spsLen, uint16(len(p.spsNalu))) // nolint: gosec // G115 ppsLen := make([]byte, 2) - binary.BigEndian.PutUint16(ppsLen, uint16(len(p.ppsNalu))) + binary.BigEndian.PutUint16(ppsLen, uint16(len(p.ppsNalu))) // nolint: gosec // G115 stapANalu := []byte{outputStapAHeader} stapANalu = append(stapANalu, spsLen...) @@ -116,6 +119,7 @@ func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte { out := make([]byte, len(nalu)) copy(out, nalu) payloads = append(payloads, out) + return } @@ -180,7 +184,7 @@ func (p *H264Payloader) Payload(mtu uint16, payload []byte) [][]byte { return payloads } -// H264Packet represents the H264 header that is stored in the payload of an RTP Packet +// H264Packet represents the H264 header that is stored in the payload of an RTP Packet. type H264Packet struct { IsAVC bool fuaBuffer []byte @@ -190,23 +194,25 @@ type H264Packet struct { func (p *H264Packet) doPackaging(buf, nalu []byte) []byte { if p.IsAVC { - buf = binary.BigEndian.AppendUint32(buf, uint32(len(nalu))) + buf = binary.BigEndian.AppendUint32(buf, uint32(len(nalu))) // nolint: gosec // G115 false positive buf = append(buf, nalu...) + return buf } buf = append(buf, annexbNALUStartCode...) buf = append(buf, nalu...) + return buf } // IsDetectedFinalPacketInSequence returns true of the packet passed in has the -// marker bit set indicated the end of a packet sequence +// marker bit set indicated the end of a packet sequence. func (p *H264Packet) IsDetectedFinalPacketInSequence(rtpPacketMarketBit bool) bool { return rtpPacketMarketBit } -// Unmarshal parses the passed byte slice and stores the result in the H264Packet this method is called upon +// Unmarshal parses the passed byte slice and stores the result in the H264Packet this method is called upon. func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { if p.zeroAllocation { return payload, nil @@ -215,7 +221,7 @@ func (p *H264Packet) Unmarshal(payload []byte) ([]byte, error) { return p.parseBody(payload) } -func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { +func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { // nolint:funlen,cyclop if len(payload) == 0 { return nil, fmt.Errorf("%w: %d <=0", errShortPacket, len(payload)) } @@ -239,12 +245,18 @@ func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { currOffset += stapaNALULengthSize if len(payload) < currOffset+naluSize { - return nil, fmt.Errorf("%w STAP-A declared size(%d) is larger than buffer(%d)", errShortPacket, naluSize, len(payload)-currOffset) + return nil, fmt.Errorf( + "%w STAP-A declared size(%d) is larger than buffer(%d)", + errShortPacket, + naluSize, + len(payload)-currOffset, + ) } result = p.doPackaging(result, payload[currOffset:currOffset+naluSize]) currOffset += naluSize } + return result, nil case naluType == fuaNALUType: @@ -265,6 +277,7 @@ func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { nalu := append([]byte{}, naluRefIdc|fragmentedNaluType) nalu = append(nalu, p.fuaBuffer...) p.fuaBuffer = nil + return p.doPackaging(nil, nalu), nil } @@ -276,12 +289,12 @@ func (p *H264Packet) parseBody(payload []byte) ([]byte, error) { // H264PartitionHeadChecker checks H264 partition head. // -// Deprecated: replaced by H264Packet.IsPartitionHead() +// Deprecated: replaced by H264Packet.IsPartitionHead(). type H264PartitionHeadChecker struct{} // IsPartitionHead checks if this is the head of a packetized nalu stream. // -// Deprecated: replaced by H264Packet.IsPartitionHead() +// Deprecated: replaced by H264Packet.IsPartitionHead(). func (*H264PartitionHeadChecker) IsPartitionHead(packet []byte) bool { return (&H264Packet{}).IsPartitionHead(packet) } diff --git a/codecs/h264_packet_test.go b/codecs/h264_packet_test.go index ca8a92c..f405782 100644 --- a/codecs/h264_packet_test.go +++ b/codecs/h264_packet_test.go @@ -8,12 +8,15 @@ import ( "testing" ) -func TestH264Payloader_Payload(t *testing.T) { +func TestH264Payloader_Payload(t *testing.T) { // nolint:funlen,cyclop pck := H264Payloader{} smallpayload := []byte{0x90, 0x90, 0x90} multiplepayload := []byte{0x00, 0x00, 0x01, 0x90, 0x00, 0x00, 0x01, 0x90} - largepayload := []byte{0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15} + largepayload := []byte{ + 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + } largePayloadPacketized := [][]byte{ {0x1c, 0x80, 0x01, 0x02, 0x03}, {0x1c, 0x00, 0x04, 0x05, 0x06}, @@ -91,13 +94,19 @@ func TestH264Payloader_Payload(t *testing.T) { } } -func TestH264Packet_Unmarshal(t *testing.T) { +func TestH264Packet_Unmarshal(t *testing.T) { // nolint:funlen,cyclop singlePayload := []byte{0x90, 0x90, 0x90} singlePayloadUnmarshaled := []byte{0x00, 0x00, 0x00, 0x01, 0x90, 0x90, 0x90} singlePayloadUnmarshaledAVC := []byte{0x00, 0x00, 0x00, 0x03, 0x90, 0x90, 0x90} - largepayload := []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15} - largepayloadAVC := []byte{0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15} + largepayload := []byte{ + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + } + largepayloadAVC := []byte{ + 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + } largePayloadPacketized := [][]byte{ {0x1c, 0x80, 0x01, 0x02, 0x03}, {0x1c, 0x00, 0x04, 0x05, 0x06}, @@ -106,14 +115,35 @@ func TestH264Packet_Unmarshal(t *testing.T) { {0x1c, 0x40, 0x13, 0x14, 0x15}, } - singlePayloadMultiNALU := []byte{0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x05, 0x68, 0x1a, 0x34, 0xe3, 0xc8} - singlePayloadMultiNALUUnmarshaled := []byte{0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x68, 0x1a, 0x34, 0xe3, 0xc8} - singlePayloadMultiNALUUnmarshaledAVC := []byte{0x00, 0x00, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x00, 0x00, 0x05, 0x68, 0x1a, 0x34, 0xe3, 0xc8} - singlePayloadWithBrokenSecondNALU := []byte{0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00} - singlePayloadWithBrokenSecondNALUUnmarshaled := []byte{0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8} - singlePayloadWithBrokenSecondUnmarshaledAVC := []byte{0x00, 0x00, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11, 0xa8} + singlePayloadMultiNALU := []byte{ + 0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, + 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x05, 0x68, 0x1a, 0x34, 0xe3, 0xc8, + } + singlePayloadMultiNALUUnmarshaled := []byte{ + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, + 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x00, 0x00, 0x01, 0x68, 0x1a, 0x34, 0xe3, 0xc8, + } + singlePayloadMultiNALUUnmarshaledAVC := []byte{ + 0x00, 0x00, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, + 0x40, 0x3c, 0x22, 0x11, 0xa8, 0x00, 0x00, 0x00, 0x05, 0x68, 0x1a, 0x34, 0xe3, 0xc8, + } + singlePayloadWithBrokenSecondNALU := []byte{ + 0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, + 0x3c, 0x22, 0x11, 0xa8, 0x00, + } + singlePayloadWithBrokenSecondNALUUnmarshaled := []byte{ + 0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, + 0x40, 0x3c, 0x22, 0x11, 0xa8, + } + singlePayloadWithBrokenSecondUnmarshaledAVC := []byte{ + 0x00, 0x00, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, + 0x40, 0x3c, 0x22, 0x11, 0xa8, + } - incompleteSinglePayloadMultiNALU := []byte{0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, 0x3c, 0x22, 0x11} + incompleteSinglePayloadMultiNALU := []byte{ + 0x78, 0x00, 0x0f, 0x67, 0x42, 0xc0, 0x1f, 0x1a, 0x32, 0x35, 0x01, 0x40, 0x7a, 0x40, + 0x3c, 0x22, 0x11, + } pkt := H264Packet{} avcPkt := H264Packet{IsAVC: true} diff --git a/codecs/h265_packet.go b/codecs/h265_packet.go index c824538..41ee44d 100644 --- a/codecs/h265_packet.go +++ b/codecs/h265_packet.go @@ -25,7 +25,7 @@ var ( // const ( - // sizeof(uint16) + // sizeof(uint16). h265NaluHeaderSize = 2 // https://datatracker.ietf.org/doc/html/rfc7798#section-4.4.2 h265NaluAggregationPacketType = 48 @@ -35,7 +35,7 @@ const ( h265NaluPACIPacketType = 50 ) -// H265NALUHeader is a H265 NAL Unit Header +// H265NALUHeader is a H265 NAL Unit Header. // https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4 /* * +---------------+---------------+ @@ -44,6 +44,7 @@ const ( * |F| Type | LayerID | TID | * +-------------+-----------------+ **/ +// . type H265NALUHeader uint16 func newH265NALUHeader(highByte, lowByte uint8) H265NALUHeader { @@ -59,13 +60,15 @@ func (h H265NALUHeader) F() bool { func (h H265NALUHeader) Type() uint8 { // 01111110 00000000 const mask = 0b01111110 << 8 - return uint8((uint16(h) & mask) >> (8 + 1)) + + return uint8((uint16(h) & mask) >> (8 + 1)) // nolint: gosec // G115 false positive } // IsTypeVCLUnit returns whether or not the NAL Unit type is a VCL NAL unit. func (h H265NALUHeader) IsTypeVCLUnit() bool { // Type is coded on 6 bits const msbMask = 0b00100000 + return (h.Type() & msbMask) == 0 } @@ -73,13 +76,15 @@ func (h H265NALUHeader) IsTypeVCLUnit() bool { func (h H265NALUHeader) LayerID() uint8 { // 00000001 11111000 const mask = (0b00000001 << 8) | 0b11111000 - return uint8((uint16(h) & mask) >> 3) + + return uint8((uint16(h) & mask) >> 3) // nolint: gosec // G115 false positive } // TID is the temporal identifier of the NAL unit +1. func (h H265NALUHeader) TID() uint8 { const mask = 0b00000111 - return uint8(uint16(h) & mask) + + return uint8(uint16(h) & mask) // nolint: gosec // G115 false positive } // IsAggregationPacket returns whether or not the packet is an Aggregation packet. @@ -133,7 +138,8 @@ func (p *H265SingleNALUnitPacket) WithDONL(value bool) { p.mightNeedDONL = value } -// Unmarshal parses the passed byte slice and stores the result in the H265SingleNALUnitPacket this method is called upon. +// Unmarshal parses the passed byte slice and stores the result in the H265SingleNALUnitPacket +// this method is called upon. func (p *H265SingleNALUnitPacket) Unmarshal(payload []byte) ([]byte, error) { // sizeof(headers) const totalHeaderSize = h265NaluHeaderSize @@ -295,7 +301,7 @@ func (p *H265AggregationPacket) WithDONL(value bool) { } // Unmarshal parses the passed byte slice and stores the result in the H265AggregationPacket this method is called upon. -func (p *H265AggregationPacket) Unmarshal(payload []byte) ([]byte, error) { +func (p *H265AggregationPacket) Unmarshal(payload []byte) ([]byte, error) { // nolint: funlen, cyclop // sizeof(headers) const totalHeaderSize = h265NaluHeaderSize if payload == nil { @@ -399,35 +405,38 @@ func (p *H265AggregationPacket) isH265Packet() {} // const ( - // sizeof(uint8) + // sizeof(uint8). h265FragmentationUnitHeaderSize = 1 ) -// H265FragmentationUnitHeader is a H265 FU Header -/* -* +---------------+ -* |0|1|2|3|4|5|6|7| -* +-+-+-+-+-+-+-+-+ -* |S|E| FuType | -* +---------------+ -**/ +// H265FragmentationUnitHeader is a H265 FU Header. +// +// +---------------+ +// |0|1|2|3|4|5|6|7| +// +-+-+-+-+-+-+-+-+ +// |S|E| FuType | +// +---------------+ +// . type H265FragmentationUnitHeader uint8 // S represents the start of a fragmented NAL unit. func (h H265FragmentationUnitHeader) S() bool { const mask = 0b10000000 + return ((h & mask) >> 7) != 0 } // E represents the end of a fragmented NAL unit. func (h H265FragmentationUnitHeader) E() bool { const mask = 0b01000000 + return ((h & mask) >> 6) != 0 } // FuType MUST be equal to the field Type of the fragmented NAL unit. func (h H265FragmentationUnitHeader) FuType() uint8 { const mask = 0b00111111 + return uint8(h) & mask } @@ -466,7 +475,8 @@ func (p *H265FragmentationUnitPacket) WithDONL(value bool) { p.mightNeedDONL = value } -// Unmarshal parses the passed byte slice and stores the result in the H265FragmentationUnitPacket this method is called upon. +// Unmarshal parses the passed byte slice and stores the result in the H265FragmentationUnitPacket +// this method is called upon. func (p *H265FragmentationUnitPacket) Unmarshal(payload []byte) ([]byte, error) { // sizeof(headers) const totalHeaderSize = h265NaluHeaderSize + h265FragmentationUnitHeaderSize @@ -571,42 +581,49 @@ func (p *H265PACIPacket) PayloadHeader() H265NALUHeader { // A copies the F bit of the PACI payload NALU. func (p *H265PACIPacket) A() bool { const mask = 0b10000000 << 8 + return (p.paciHeaderFields & mask) != 0 } // CType copies the Type field of the PACI payload NALU. func (p *H265PACIPacket) CType() uint8 { const mask = 0b01111110 << 8 - return uint8((p.paciHeaderFields & mask) >> (8 + 1)) + + return uint8((p.paciHeaderFields & mask) >> (8 + 1)) // nolint: gosec // G115 false positive } // PHSsize indicates the size of the PHES field. func (p *H265PACIPacket) PHSsize() uint8 { const mask = (0b00000001 << 8) | 0b11110000 - return uint8((p.paciHeaderFields & mask) >> 4) + + return uint8((p.paciHeaderFields & mask) >> 4) // nolint: gosec // G115 false positive } // F0 indicates the presence of a Temporal Scalability support extension in the PHES. func (p *H265PACIPacket) F0() bool { const mask = 0b00001000 + return (p.paciHeaderFields & mask) != 0 } // F1 must be zero, reserved for future extensions. func (p *H265PACIPacket) F1() bool { const mask = 0b00000100 + return (p.paciHeaderFields & mask) != 0 } // F2 must be zero, reserved for future extensions. func (p *H265PACIPacket) F2() bool { const mask = 0b00000010 + return (p.paciHeaderFields & mask) != 0 } // Y must be zero, reserved for future extensions. func (p *H265PACIPacket) Y() bool { const mask = 0b00000001 + return (p.paciHeaderFields & mask) != 0 } @@ -627,6 +644,7 @@ func (p *H265PACIPacket) TSCI() *H265TSCI { } tsci := H265TSCI((uint32(p.phes[0]) << 16) | (uint32(p.phes[1]) << 8) | uint32(p.phes[0])) + return &tsci } @@ -656,6 +674,7 @@ func (p *H265PACIPacket) Unmarshal(payload []byte) ([]byte, error) { if len(payload) < int(headerExtensionSize)+1 { p.paciHeaderFields = 0 + return nil, errShortPacket } @@ -685,35 +704,40 @@ type H265TSCI uint32 func (h H265TSCI) TL0PICIDX() uint8 { const m1 = 0xFFFF0000 const m2 = 0xFF00 - return uint8((((h & m1) >> 16) & m2) >> 8) + + return uint8((((h & m1) >> 16) & m2) >> 8) // nolint: gosec // G115 false positive } // IrapPicID see RFC7798 for more details. func (h H265TSCI) IrapPicID() uint8 { const m1 = 0xFFFF0000 const m2 = 0x00FF - return uint8(((h & m1) >> 16) & m2) + + return uint8(((h & m1) >> 16) & m2) // nolint: gosec // G115 false positive } // S see RFC7798 for more details. func (h H265TSCI) S() bool { const m1 = 0xFF00 const m2 = 0b10000000 - return (uint8((h&m1)>>8) & m2) != 0 + + return (uint8((h&m1)>>8) & m2) != 0 // nolint: gosec // G115 false positive } // E see RFC7798 for more details. func (h H265TSCI) E() bool { const m1 = 0xFF00 const m2 = 0b01000000 - return (uint8((h&m1)>>8) & m2) != 0 + + return (uint8((h&m1)>>8) & m2) != 0 // nolint: gosec // G115 false positive } // RES see RFC7798 for more details. func (h H265TSCI) RES() uint8 { const m1 = 0xFF00 const m2 = 0b00111111 - return uint8((h&m1)>>8) & m2 + + return uint8((h&m1)>>8) & m2 // nolint: gosec // G115 false positive } // @@ -798,8 +822,8 @@ func (p *H265Packet) WithDepackBufNALUs(value uint16) { p.depackBufNALUs = value } -// Unmarshal parses the passed byte slice and stores the result in the H265Packet this method is called upon -func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) { //nolint: gocognit +// Unmarshal parses the passed byte slice and stores the result in the H265Packet this method is called upon. +func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) { // nolint:cyclop if payload == nil { return nil, errNilPacket } else if len(payload) <= h265NaluHeaderSize { diff --git a/codecs/h265_packet_test.go b/codecs/h265_packet_test.go index b3c2079..0921a90 100644 --- a/codecs/h265_packet_test.go +++ b/codecs/h265_packet_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestH265_NALU_Header(t *testing.T) { +func TestH265_NALU_Header(t *testing.T) { // nolint: funlen tt := [...]struct { RawHeader []byte @@ -105,7 +105,7 @@ func TestH265_NALU_Header(t *testing.T) { } } -func TestH265_FU_Header(t *testing.T) { +func TestH265_FU_Header(t *testing.T) { // nolint:funlen tt := [...]struct { header H265FragmentationUnitHeader @@ -172,7 +172,7 @@ func TestH265_FU_Header(t *testing.T) { } } -func TestH265_SingleNALUnitPacket(t *testing.T) { +func TestH265_SingleNALUnitPacket(t *testing.T) { // nolint:funlen,cyclop tt := [...]struct { Raw []byte WithDONL bool @@ -269,7 +269,7 @@ func TestH265_SingleNALUnitPacket(t *testing.T) { } } -func TestH265_AggregationPacket(t *testing.T) { +func TestH265_AggregationPacket(t *testing.T) { // nolint:funlen,cyclop tt := [...]struct { Raw []byte WithDONL bool @@ -402,7 +402,8 @@ func TestH265_AggregationPacket(t *testing.T) { t.Fatal("invalid first unit NALUSize") } - if cur.ExpectedPacket.FirstUnit().DONL() != nil && *cur.ExpectedPacket.FirstUnit().DONL() != *parsed.FirstUnit().DONL() { + if cur.ExpectedPacket.FirstUnit().DONL() != nil && + *cur.ExpectedPacket.FirstUnit().DONL() != *parsed.FirstUnit().DONL() { t.Fatal("invalid first unit DONL") } @@ -435,7 +436,7 @@ func TestH265_AggregationPacket(t *testing.T) { } } -func TestH265_FragmentationUnitPacket(t *testing.T) { +func TestH265_FragmentationUnitPacket(t *testing.T) { // nolint:funlen,cyclop tt := [...]struct { Raw []byte WithDONL bool @@ -594,7 +595,7 @@ func TestH265_TemporalScalabilityControlInformation(t *testing.T) { } } -func TestH265_PACI_Packet(t *testing.T) { +func TestH265_PACI_Packet(t *testing.T) { // nolint:funlen, cyclop tt := [...]struct { Raw []byte ExpectedFU *H265PACIPacket @@ -722,7 +723,7 @@ func TestH265_PACI_Packet(t *testing.T) { } } -func TestH265_Packet(t *testing.T) { +func TestH265_Packet(t *testing.T) { // nolint: funlen tt := [...]struct { Raw []byte WithDONL bool @@ -851,6 +852,7 @@ func TestH265IsPartitionHead(t *testing.T) { func TestH265_Packet_Real(t *testing.T) { // Tests decoding of real H265 payloads extracted from a Wireshark dump. + // nolint: lll tt := [...]string{ "\x40\x01\x0c\x01\xff\xff\x01\x60\x00\x00\x03\x00\xb0\x00\x00\x03\x00\x00\x03\x00\x7b\xac\x09", "\x42\x01\x01\x01\x60\x00\x00\x03\x00\xb0\x00\x00\x03\x00\x00\x03\x00\x7b\xa0\x03\xc0\x80\x10\xe5\x8d\xae\x49\x32\xf4\xdc\x04\x04\x04\x02", diff --git a/codecs/opus_packet.go b/codecs/opus_packet.go index 00ee903..89aaae3 100644 --- a/codecs/opus_packet.go +++ b/codecs/opus_packet.go @@ -3,10 +3,10 @@ package codecs -// OpusPayloader payloads Opus packets +// OpusPayloader payloads Opus packets. type OpusPayloader struct{} -// Payload fragments an Opus packet across one or more byte arrays +// Payload fragments an Opus packet across one or more byte arrays. func (p *OpusPayloader) Payload(_ uint16, payload []byte) [][]byte { if payload == nil { return [][]byte{} @@ -14,17 +14,18 @@ func (p *OpusPayloader) Payload(_ uint16, payload []byte) [][]byte { out := make([]byte, len(payload)) copy(out, payload) + return [][]byte{out} } -// OpusPacket represents the Opus header that is stored in the payload of an RTP Packet +// OpusPacket represents the Opus header that is stored in the payload of an RTP Packet. type OpusPacket struct { Payload []byte audioDepacketizer } -// Unmarshal parses the passed byte slice and stores the result in the OpusPacket this method is called upon +// Unmarshal parses the passed byte slice and stores the result in the OpusPacket this method is called upon. func (p *OpusPacket) Unmarshal(packet []byte) ([]byte, error) { if packet == nil { return nil, errNilPacket @@ -33,17 +34,18 @@ func (p *OpusPacket) Unmarshal(packet []byte) ([]byte, error) { } p.Payload = packet + return packet, nil } // OpusPartitionHeadChecker checks Opus partition head. // -// Deprecated: replaced by OpusPacket.IsPartitionHead() +// Deprecated: replaced by OpusPacket.IsPartitionHead(). type OpusPartitionHeadChecker struct{} // IsPartitionHead checks whether if this is a head of the Opus partition. // -// Deprecated: replaced by OpusPacket.IsPartitionHead() +// Deprecated: replaced by OpusPacket.IsPartitionHead(). func (*OpusPartitionHeadChecker) IsPartitionHead(packet []byte) bool { return (&OpusPacket{}).IsPartitionHead(packet) } diff --git a/codecs/vp8_packet.go b/codecs/vp8_packet.go index 87560ab..2634d5a 100644 --- a/codecs/vp8_packet.go +++ b/codecs/vp8_packet.go @@ -3,7 +3,7 @@ package codecs -// VP8Payloader payloads VP8 packets +// VP8Payloader payloads VP8 packets. type VP8Payloader struct { EnablePictureID bool pictureID uint16 @@ -13,8 +13,8 @@ const ( vp8HeaderSize = 1 ) -// Payload fragments a VP8 packet across one or more byte arrays -func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { +// Payload fragments a VP8 packet across one or more byte arrays. +func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { // nolint:funlen,cyclop /* * https://tools.ietf.org/html/rfc7741#section-4.2 * @@ -74,12 +74,12 @@ func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { case vp8HeaderSize + 2: out[0] |= 0x80 out[1] |= 0x80 - out[2] |= uint8(p.pictureID & 0x7F) + out[2] |= uint8(p.pictureID & 0x7F) // nolint: gosec // G115 false positive case vp8HeaderSize + 3: out[0] |= 0x80 out[1] |= 0x80 - out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F) - out[3] |= uint8(p.pictureID & 0xFF) + out[2] |= 0x80 | uint8((p.pictureID>>8)&0x7F) // nolint: gosec // G115 false positive + out[3] |= uint8(p.pictureID & 0xFF) // nolint: gosec // G115 false positive } } @@ -96,7 +96,7 @@ func (p *VP8Payloader) Payload(mtu uint16, payload []byte) [][]byte { return payloads } -// VP8Packet represents the VP8 header that is stored in the payload of an RTP Packet +// VP8Packet represents the VP8 header that is stored in the payload of an RTP Packet. type VP8Packet struct { // Required Header X uint8 /* extended control bits present */ @@ -122,8 +122,8 @@ type VP8Packet struct { videoDepacketizer } -// Unmarshal parses the passed byte slice and stores the result in the VP8Packet this method is called upon -func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) { //nolint: gocognit +// Unmarshal parses the passed byte slice and stores the result in the VP8Packet this method is called upon. +func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) { // nolint: gocognit, funlen, cyclop if payload == nil { return nil, errNilPacket } @@ -158,6 +158,7 @@ func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) { //nolint: gocogn p.K = 0 } + // nolint: nestif if p.I == 1 { // PID present? if payloadIndex >= payloadLen { return nil, errShortPacket @@ -186,7 +187,7 @@ func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) { //nolint: gocogn p.TL0PICIDX = 0 } - if p.T == 1 || p.K == 1 { + if p.T == 1 || p.K == 1 { // nolint: nestif if payloadIndex >= payloadLen { return nil, errShortPacket } @@ -210,25 +211,27 @@ func (p *VP8Packet) Unmarshal(payload []byte) ([]byte, error) { //nolint: gocogn } p.Payload = payload[payloadIndex:] + return p.Payload, nil } // VP8PartitionHeadChecker checks VP8 partition head // -// Deprecated: replaced by VP8Packet.IsPartitionHead() +// Deprecated: replaced by VP8Packet.IsPartitionHead(). type VP8PartitionHeadChecker struct{} // IsPartitionHead checks whether if this is a head of the VP8 partition. // -// Deprecated: replaced by VP8Packet.IsPartitionHead() +// Deprecated: replaced by VP8Packet.IsPartitionHead(). func (*VP8PartitionHeadChecker) IsPartitionHead(packet []byte) bool { return (&VP8Packet{}).IsPartitionHead(packet) } -// IsPartitionHead checks whether if this is a head of the VP8 partition +// IsPartitionHead checks whether if this is a head of the VP8 partition. func (*VP8Packet) IsPartitionHead(payload []byte) bool { if len(payload) < 1 { return false } + return (payload[0] & 0x10) != 0 } diff --git a/codecs/vp8_packet_test.go b/codecs/vp8_packet_test.go index 3abb520..4224074 100644 --- a/codecs/vp8_packet_test.go +++ b/codecs/vp8_packet_test.go @@ -9,7 +9,7 @@ import ( "testing" ) -func TestVP8Packet_Unmarshal(t *testing.T) { +func TestVP8Packet_Unmarshal(t *testing.T) { // nolint: funlen, cyclop pck := VP8Packet{} // Nil packet @@ -134,7 +134,7 @@ func TestVP8Packet_Unmarshal(t *testing.T) { } } -func TestVP8Payloader_Payload(t *testing.T) { +func TestVP8Payloader_Payload(t *testing.T) { // nolint: funlen testCases := map[string]struct { payloader VP8Payloader mtu uint16 diff --git a/codecs/vp9/bits.go b/codecs/vp9/bits.go index a6a3c1f..97f7022 100644 --- a/codecs/vp9/bits.go +++ b/codecs/vp9/bits.go @@ -11,6 +11,7 @@ func hasSpace(buf []byte, pos int, n int) error { if n > ((len(buf) * 8) - pos) { return errNotEnoughBits } + return nil } @@ -26,6 +27,7 @@ func readFlag(buf []byte, pos *int) (bool, error) { func readFlagUnsafe(buf []byte, pos *int) bool { b := (buf[*pos>>0x03] >> (7 - (*pos & 0x07))) & 0x01 *pos++ + return b == 1 } @@ -41,25 +43,26 @@ func readBits(buf []byte, pos *int, n int) (uint64, error) { func readBitsUnsafe(buf []byte, pos *int, n int) uint64 { res := 8 - (*pos & 0x07) if n < res { - v := uint64((buf[*pos>>0x03] >> (res - n)) & (1<>0x03] >> (res - n)) & (1<>0x03] & (1<>0x03] & (1<= 8 { - v = (v << 8) | uint64(buf[*pos>>0x03]) + bits = (bits << 8) | uint64(buf[*pos>>0x03]) *pos += 8 n -= 8 } if n > 0 { - v = (v << n) | uint64(buf[*pos>>0x03]>>(8-n)) + bits = (bits << n) | uint64(buf[*pos>>0x03]>>(8-n)) *pos += n } - return v + return bits } diff --git a/codecs/vp9/header.go b/codecs/vp9/header.go index 30e15bc..ed49335 100644 --- a/codecs/vp9/header.go +++ b/codecs/vp9/header.go @@ -25,7 +25,7 @@ type HeaderColorConfig struct { SubsamplingY bool } -func (c *HeaderColorConfig) unmarshal(profile uint8, buf []byte, pos *int) error { +func (c *HeaderColorConfig) unmarshal(profile uint8, buf []byte, pos *int) error { // nolint:cyclop if profile >= 2 { var err error c.TenOrTwelveBit, err = readFlag(buf, pos) @@ -46,9 +46,9 @@ func (c *HeaderColorConfig) unmarshal(profile uint8, buf []byte, pos *int) error if err != nil { return err } - c.ColorSpace = uint8(tmp) + c.ColorSpace = uint8(tmp) // nolint: gosec // G115, no overflow we read 3 bits - if c.ColorSpace != 7 { + if c.ColorSpace != 7 { // nolint: nestif var err error c.ColorRange, err = readFlag(buf, pos) if err != nil { @@ -98,8 +98,9 @@ func (s *HeaderFrameSize) unmarshal(buf []byte, pos *int) error { return err } - s.FrameWidthMinus1 = uint16(readBitsUnsafe(buf, pos, 16)) - s.FrameHeightMinus1 = uint16(readBitsUnsafe(buf, pos, 16)) + s.FrameWidthMinus1 = uint16(readBitsUnsafe(buf, pos, 16)) // nolint: gosec // G115 no overflow, we read 16 bits + s.FrameHeightMinus1 = uint16(readBitsUnsafe(buf, pos, 16)) // nolint: gosec // G115 + return nil } @@ -118,7 +119,7 @@ type Header struct { } // Unmarshal decodes a Header. -func (h *Header) Unmarshal(buf []byte) error { +func (h *Header) Unmarshal(buf []byte) error { // nolint:funlen,cyclop pos := 0 err := hasSpace(buf, pos, 4) @@ -131,8 +132,8 @@ func (h *Header) Unmarshal(buf []byte) error { return errInvalidFrameMarker } - profileLowBit := uint8(readBitsUnsafe(buf, &pos, 1)) - profileHighBit := uint8(readBitsUnsafe(buf, &pos, 1)) + profileLowBit := uint8(readBitsUnsafe(buf, &pos, 1)) // nolint: gosec // no overflow, we read 1 bit + profileHighBit := uint8(readBitsUnsafe(buf, &pos, 1)) // nolint: gosec // G115 h.Profile = profileHighBit<<1 + profileLowBit if h.Profile == 3 { @@ -154,7 +155,8 @@ func (h *Header) Unmarshal(buf []byte) error { if err != nil { return err } - h.FrameToShowMapIdx = uint8(tmp) + h.FrameToShowMapIdx = uint8(tmp) // nolint: gosec // no overflow, we read 3 bits + return nil } @@ -167,23 +169,23 @@ func (h *Header) Unmarshal(buf []byte) error { h.ShowFrame = readFlagUnsafe(buf, &pos) h.ErrorResilientMode = readFlagUnsafe(buf, &pos) - if !h.NonKeyFrame { + if !h.NonKeyFrame { // nolint: nestif err := hasSpace(buf, pos, 24) if err != nil { return err } - frameSyncByte0 := uint8(readBitsUnsafe(buf, &pos, 8)) + frameSyncByte0 := uint8(readBitsUnsafe(buf, &pos, 8)) // nolint: gosec // no overflow, we read 8 bits if frameSyncByte0 != 0x49 { return errWrongFrameSyncByte0 } - frameSyncByte1 := uint8(readBitsUnsafe(buf, &pos, 8)) + frameSyncByte1 := uint8(readBitsUnsafe(buf, &pos, 8)) // nolint: gosec // no overflow, we read 8 bits if frameSyncByte1 != 0x83 { return errWrongFrameSyncByte1 } - frameSyncByte2 := uint8(readBitsUnsafe(buf, &pos, 8)) + frameSyncByte2 := uint8(readBitsUnsafe(buf, &pos, 8)) // nolint: gosec // no overflow, we read 8 bits if frameSyncByte2 != 0x42 { return errWrongFrameSyncByte2 } @@ -209,6 +211,7 @@ func (h Header) Width() uint16 { if h.FrameSize == nil { return 0 } + return h.FrameSize.FrameWidthMinus1 + 1 } @@ -217,5 +220,6 @@ func (h Header) Height() uint16 { if h.FrameSize == nil { return 0 } + return h.FrameSize.FrameHeightMinus1 + 1 } diff --git a/codecs/vp9/header_test.go b/codecs/vp9/header_test.go index 41fb46a..eccc71b 100644 --- a/codecs/vp9/header_test.go +++ b/codecs/vp9/header_test.go @@ -8,7 +8,7 @@ import ( "testing" ) -func TestHeaderUnmarshal(t *testing.T) { +func TestHeaderUnmarshal(t *testing.T) { // nolint: funlen cases := []struct { name string byts []byte diff --git a/codecs/vp9_packet.go b/codecs/vp9_packet.go index e2ffab7..4c2306e 100644 --- a/codecs/vp9_packet.go +++ b/codecs/vp9_packet.go @@ -11,7 +11,7 @@ import ( // Use global random generator to properly seed by crypto grade random. var globalMathRandomGenerator = randutil.NewMathRandomGenerator() // nolint:gochecknoglobals -// VP9Payloader payloads VP9 packets +// VP9Payloader payloads VP9 packets. type VP9Payloader struct { // whether to use flexible mode or non-flexible mode. FlexibleMode bool @@ -28,12 +28,12 @@ const ( maxVP9RefPics = 3 ) -// Payload fragments an VP9 packet across one or more byte arrays +// Payload fragments an VP9 packet across one or more byte arrays. func (p *VP9Payloader) Payload(mtu uint16, payload []byte) [][]byte { if !p.initialized { if p.InitialPictureIDFn == nil { p.InitialPictureIDFn = func() uint16 { - return uint16(globalMathRandomGenerator.Intn(0x7FFF)) + return uint16(globalMathRandomGenerator.Intn(0x7FFF)) // nolint: gosec } } p.pictureID = p.InitialPictureIDFn() & 0x7FFF @@ -110,7 +110,7 @@ func (p *VP9Payloader) payloadFlexible(mtu uint16, payload []byte) [][]byte { return payloads } -func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { +func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { // nolint:funlen,cyclop /* * Non-flexible mode (F=0) * 0 1 2 3 4 5 6 7 @@ -130,8 +130,8 @@ func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { * +-+-+-+-+-+-+-+-+ */ - var h vp9.Header - err := h.Unmarshal(payload) + var header vp9.Header + err := header.Unmarshal(payload) if err != nil { return [][]byte{} } @@ -142,7 +142,7 @@ func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { for payloadDataRemaining > 0 { var headerSize int - if !h.NonKeyFrame && payloadDataIndex == 0 { + if !header.NonKeyFrame && payloadDataIndex == 0 { headerSize = 3 + 8 } else { headerSize = 3 @@ -158,7 +158,7 @@ func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { out[0] = 0x80 | 0x01 // I=1, Z=1 - if h.NonKeyFrame { + if header.NonKeyFrame { out[0] |= 0x40 // P=1 } if payloadDataIndex == 0 { @@ -172,18 +172,18 @@ func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { out[2] = byte(p.pictureID) off := 3 - if !h.NonKeyFrame && payloadDataIndex == 0 { + if !header.NonKeyFrame && payloadDataIndex == 0 { out[0] |= 0x02 // V=1 out[off] = 0x10 | 0x08 // N_S=0, Y=1, G=1 off++ - width := h.Width() + width := header.Width() out[off] = byte(width >> 8) off++ out[off] = byte(width & 0xFF) off++ - height := h.Height() + height := header.Height() out[off] = byte(height >> 8) off++ out[off] = byte(height & 0xFF) @@ -208,7 +208,7 @@ func (p *VP9Payloader) payloadNonFlexible(mtu uint16, payload []byte) [][]byte { return payloads } -// VP9Packet represents the VP9 header that is stored in the payload of an RTP Packet +// VP9Packet represents the VP9 header that is stored in the payload of an RTP Packet. type VP9Packet struct { // Required header I bool // PictureID is present @@ -249,8 +249,8 @@ type VP9Packet struct { videoDepacketizer } -// Unmarshal parses the passed byte slice and stores the result in the VP9Packet this method is called upon -func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) { +// Unmarshal parses the passed byte slice and stores the result in the VP9Packet this method is called upon. +func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) { // nolint:cyclop if packet == nil { return nil, errNilPacket } @@ -299,6 +299,7 @@ func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) { } p.Payload = packet[pos:] + return p.Payload, nil } @@ -310,6 +311,7 @@ func (p *VP9Packet) Unmarshal(packet []byte) ([]byte, error) { * M: | EXTENDED PID | * +-+-+-+-+-+-+-+-+ **/ +// . func (p *VP9Packet) parsePictureID(packet []byte, pos int) (int, error) { if len(packet) <= pos { return pos, errShortPacket @@ -324,6 +326,7 @@ func (p *VP9Packet) parsePictureID(packet []byte, pos int) (int, error) { p.PictureID = p.PictureID<<8 | uint16(packet[pos]) } pos++ + return pos, nil } @@ -346,6 +349,7 @@ func (p *VP9Packet) parseLayerInfo(packet []byte, pos int) (int, error) { * L: | T |U| S |D| * +-+-+-+-+-+-+-+-+ **/ +// . func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) { if len(packet) <= pos { return pos, errShortPacket @@ -361,6 +365,7 @@ func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) { } pos++ + return pos, nil } @@ -372,6 +377,7 @@ func (p *VP9Packet) parseLayerInfoCommon(packet []byte, pos int) (int, error) { * | TL0PICIDX | * +-+-+-+-+-+-+-+-+ **/ +// . func (p *VP9Packet) parseLayerInfoNonFlexibleMode(packet []byte, pos int) (int, error) { if len(packet) <= pos { return pos, errShortPacket @@ -379,16 +385,19 @@ func (p *VP9Packet) parseLayerInfoNonFlexibleMode(packet []byte, pos int) (int, p.TL0PICIDX = packet[pos] pos++ + return pos, nil } -// Reference indices: +// Reference indices: . /* * +-+-+-+-+-+-+-+-+ P=1,F=1: At least one reference index * P,F: | P_DIFF |N| up to 3 times has to be specified. * +-+-+-+-+-+-+-+-+ N=1: An additional P_DIFF follows * current P_DIFF. +* **/ +// . func (p *VP9Packet) parseRefIndices(packet []byte, pos int) (int, error) { for { if len(packet) <= pos { @@ -428,7 +437,8 @@ func (p *VP9Packet) parseRefIndices(packet []byte, pos int) (int, error) { * | P_DIFF | (OPTIONAL) . R times . * +-+-+-+-+-+-+-+-+ -| -| **/ -func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) { +// . +func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) { // nolint: cyclop if len(packet) <= pos { return pos, errShortPacket } @@ -492,20 +502,21 @@ func (p *VP9Packet) parseSSData(packet []byte, pos int) (int, error) { // VP9PartitionHeadChecker checks VP9 partition head. // -// Deprecated: replaced by VP9Packet.IsPartitionHead() +// Deprecated: replaced by VP9Packet.IsPartitionHead(). type VP9PartitionHeadChecker struct{} // IsPartitionHead checks whether if this is a head of the VP9 partition. // -// Deprecated: replaced by VP9Packet.IsPartitionHead() +// Deprecated: replaced by VP9Packet.IsPartitionHead(). func (*VP9PartitionHeadChecker) IsPartitionHead(packet []byte) bool { return (&VP9Packet{}).IsPartitionHead(packet) } -// IsPartitionHead checks whether if this is a head of the VP9 partition +// IsPartitionHead checks whether if this is a head of the VP9 partition. func (*VP9Packet) IsPartitionHead(payload []byte) bool { if len(payload) < 1 { return false } + return (payload[0] & 0x08) != 0 } diff --git a/codecs/vp9_packet_test.go b/codecs/vp9_packet_test.go index 9591f22..4534903 100644 --- a/codecs/vp9_packet_test.go +++ b/codecs/vp9_packet_test.go @@ -10,7 +10,7 @@ import ( "testing" ) -func TestVP9Packet_Unmarshal(t *testing.T) { +func TestVP9Packet_Unmarshal(t *testing.T) { // nolint: funlen cases := map[string]struct { b []byte pkt VP9Packet @@ -186,34 +186,35 @@ func TestVP9Packet_Unmarshal(t *testing.T) { err: errShortPacket, }, } - for name, c := range cases { - c := c + for name, testCase := range cases { + testCase := testCase + t.Run(name, func(t *testing.T) { p := VP9Packet{} - raw, err := p.Unmarshal(c.b) - if c.err == nil { + raw, err := p.Unmarshal(testCase.b) + if testCase.err == nil { // nolint: nestif if raw == nil { t.Error("Result shouldn't be nil in case of success") } if err != nil { t.Error("Error should be nil in case of success") } - if !reflect.DeepEqual(c.pkt, p) { - t.Errorf("Unmarshalled packet expected to be:\n %v\ngot:\n %v", c.pkt, p) + if !reflect.DeepEqual(testCase.pkt, p) { + t.Errorf("Unmarshalled packet expected to be:\n %v\ngot:\n %v", testCase.pkt, p) } } else { if raw != nil { t.Error("Result should be nil in case of error") } - if !errors.Is(err, c.err) { - t.Errorf("Error should be '%v', got '%v'", c.err, err) + if !errors.Is(err, testCase.err) { + t.Errorf("Error should be '%v', got '%v'", testCase.err, err) } } }) } } -func TestVP9Payloader_Payload(t *testing.T) { +func TestVP9Payloader_Payload(t *testing.T) { // nolint: funlen, cyclop r0 := int(rand.New(rand.NewSource(0)).Int31n(0x7FFF)) //nolint:gosec var rands [][2]byte for i := 0; i < 10; i++ { @@ -341,21 +342,21 @@ func TestVP9Payloader_Payload(t *testing.T) { }, } - for name, c := range cases { + for name, testCase := range cases { t.Run(name, func(t *testing.T) { pck := VP9Payloader{ - FlexibleMode: c.flexible, + FlexibleMode: testCase.flexible, InitialPictureIDFn: func() uint16 { return uint16(rand.New(rand.NewSource(0)).Int31n(0x7FFF)) //nolint:gosec }, } res := [][]byte{} - for _, b := range c.b { - res = append(res, pck.Payload(c.mtu, b)...) + for _, b := range testCase.b { + res = append(res, pck.Payload(testCase.mtu, b)...) } - if !reflect.DeepEqual(c.res, res) { - t.Errorf("Payloaded packet expected to be:\n %v\ngot:\n %v", c.res, res) + if !reflect.DeepEqual(testCase.res, res) { + t.Errorf("Payloaded packet expected to be:\n %v\ngot:\n %v", testCase.res, res) } }) } @@ -370,23 +371,23 @@ func TestVP9Payloader_Payload(t *testing.T) { pPrev := VP9Packet{} for i := 0; i < 0x8000; i++ { res := pck.Payload(4, []byte{0x01}) - p := VP9Packet{} - _, err := p.Unmarshal(res[0]) + packet := VP9Packet{} + _, err := packet.Unmarshal(res[0]) if err != nil { t.Fatalf("Unexpected error: %v", err) } if i > 0 { if pPrev.PictureID == 0x7FFF { - if p.PictureID != 0 { - t.Errorf("Picture ID next to 0x7FFF must be 0, got %d", p.PictureID) + if packet.PictureID != 0 { + t.Errorf("Picture ID next to 0x7FFF must be 0, got %d", packet.PictureID) } - } else if pPrev.PictureID+1 != p.PictureID { - t.Errorf("Picture ID next must be incremented by 1: %d -> %d", pPrev.PictureID, p.PictureID) + } else if pPrev.PictureID+1 != packet.PictureID { + t.Errorf("Picture ID next must be incremented by 1: %d -> %d", pPrev.PictureID, packet.PictureID) } } - pPrev = p + pPrev = packet } }) } diff --git a/depacketizer.go b/depacketizer.go index d10ad89..3027ae6 100644 --- a/depacketizer.go +++ b/depacketizer.go @@ -3,7 +3,7 @@ package rtp -// Depacketizer depacketizes a RTP payload, removing any RTP specific data from the payload +// Depacketizer depacketizes a RTP payload, removing any RTP specific data from the payload. type Depacketizer interface { // Unmarshal parses the RTP payload and returns media. // Metadata may be stored on the Depacketizer itself diff --git a/error.go b/error.go index ac3ece4..eb78874 100644 --- a/error.go +++ b/error.go @@ -14,11 +14,19 @@ var ( errHeaderExtensionsNotEnabled = errors.New("h.Extension not enabled") errHeaderExtensionNotFound = errors.New("extension not found") - errRFC8285OneByteHeaderIDRange = errors.New("header extension id must be between 1 and 14 for RFC 5285 one byte extensions") - errRFC8285OneByteHeaderSize = errors.New("header extension payload must be 16bytes or less for RFC 5285 one byte extensions") + errRFC8285OneByteHeaderIDRange = errors.New( + "header extension id must be between 1 and 14 for RFC 5285 one byte extensions", + ) + errRFC8285OneByteHeaderSize = errors.New( + "header extension payload must be 16bytes or less for RFC 5285 one byte extensions", + ) - errRFC8285TwoByteHeaderIDRange = errors.New("header extension id must be between 1 and 255 for RFC 5285 two byte extensions") - errRFC8285TwoByteHeaderSize = errors.New("header extension payload must be 255bytes or less for RFC 5285 two byte extensions") + errRFC8285TwoByteHeaderIDRange = errors.New( + "header extension id must be between 1 and 255 for RFC 5285 two byte extensions", + ) + errRFC8285TwoByteHeaderSize = errors.New( + "header extension payload must be 255bytes or less for RFC 5285 two byte extensions", + ) errRFC3550HeaderIDRange = errors.New("header extension id must be 0 for non-RFC 5285 extensions") diff --git a/header_extension.go b/header_extension.go index cdb16bd..b36d09a 100644 --- a/header_extension.go +++ b/header_extension.go @@ -45,6 +45,7 @@ func (e *OneByteHeaderExtension) Set(id uint8, buf []byte) error { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -54,13 +55,15 @@ func (e *OneByteHeaderExtension) Set(id uint8, buf []byte) error { if extid == id { e.payload = append(e.payload[:n+1], append(buf, e.payload[n+1+payloadLen:]...)...) + return nil } n += payloadLen } - e.payload = append(e.payload, (id<<4 | uint8(len(buf)-1))) + e.payload = append(e.payload, (id<<4 | uint8(len(buf)-1))) // nolint: gosec // G115 e.payload = append(e.payload, buf...) binary.BigEndian.PutUint16(e.payload[2:4], binary.BigEndian.Uint16(e.payload[2:4])+1) + return nil } @@ -70,6 +73,7 @@ func (e *OneByteHeaderExtension) GetIDs() []uint8 { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -84,6 +88,7 @@ func (e *OneByteHeaderExtension) GetIDs() []uint8 { ids = append(ids, extid) n += payloadLen } + return ids } @@ -92,6 +97,7 @@ func (e *OneByteHeaderExtension) Get(id uint8) []byte { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -104,6 +110,7 @@ func (e *OneByteHeaderExtension) Get(id uint8) []byte { } n += payloadLen } + return nil } @@ -112,6 +119,7 @@ func (e *OneByteHeaderExtension) Del(id uint8) error { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -120,10 +128,12 @@ func (e *OneByteHeaderExtension) Del(id uint8) error { if extid == id { e.payload = append(e.payload[:n], e.payload[n+1+payloadLen:]...) + return nil } n += payloadLen + 1 } + return errHeaderExtensionNotFound } @@ -134,6 +144,7 @@ func (e *OneByteHeaderExtension) Unmarshal(buf []byte) (int, error) { return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2]) } e.payload = buf + return len(buf), nil } @@ -148,6 +159,7 @@ func (e OneByteHeaderExtension) MarshalTo(buf []byte) (int, error) { if size > len(buf) { return 0, io.ErrShortBuffer } + return copy(buf, e.payload), nil } @@ -173,6 +185,7 @@ func (e *TwoByteHeaderExtension) Set(id uint8, buf []byte) error { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -184,13 +197,15 @@ func (e *TwoByteHeaderExtension) Set(id uint8, buf []byte) error { if extid == id { e.payload = append(e.payload[:n+2], append(buf, e.payload[n+2+payloadLen:]...)...) + return nil } n += payloadLen } - e.payload = append(e.payload, id, uint8(len(buf))) + e.payload = append(e.payload, id, uint8(len(buf))) // nolint: gosec // G115 e.payload = append(e.payload, buf...) binary.BigEndian.PutUint16(e.payload[2:4], binary.BigEndian.Uint16(e.payload[2:4])+1) + return nil } @@ -200,6 +215,7 @@ func (e *TwoByteHeaderExtension) GetIDs() []uint8 { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -212,6 +228,7 @@ func (e *TwoByteHeaderExtension) GetIDs() []uint8 { ids = append(ids, extid) n += payloadLen } + return ids } @@ -220,6 +237,7 @@ func (e *TwoByteHeaderExtension) Get(id uint8) []byte { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -234,6 +252,7 @@ func (e *TwoByteHeaderExtension) Get(id uint8) []byte { } n += payloadLen } + return nil } @@ -242,6 +261,7 @@ func (e *TwoByteHeaderExtension) Del(id uint8) error { for n := 4; n < len(e.payload); { if e.payload[n] == 0x00 { // padding n++ + continue } @@ -251,10 +271,12 @@ func (e *TwoByteHeaderExtension) Del(id uint8) error { if extid == id { e.payload = append(e.payload[:n], e.payload[n+2+payloadLen:]...) + return nil } n += payloadLen + 2 } + return errHeaderExtensionNotFound } @@ -265,6 +287,7 @@ func (e *TwoByteHeaderExtension) Unmarshal(buf []byte) (int, error) { return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2]) } e.payload = buf + return len(buf), nil } @@ -279,6 +302,7 @@ func (e TwoByteHeaderExtension) MarshalTo(buf []byte) (int, error) { if size > len(buf) { return 0, io.ErrShortBuffer } + return copy(buf, e.payload), nil } @@ -298,6 +322,7 @@ func (e *RawExtension) Set(id uint8, payload []byte) error { return fmt.Errorf("%w actual(%d)", errRFC3550HeaderIDRange, id) } e.payload = payload + return nil } @@ -311,6 +336,7 @@ func (e *RawExtension) Get(id uint8) []byte { if id == 0 { return e.payload } + return nil } @@ -318,8 +344,10 @@ func (e *RawExtension) Get(id uint8) []byte { func (e *RawExtension) Del(id uint8) error { if id == 0 { e.payload = nil + return nil } + return fmt.Errorf("%w actual(%d)", errRFC3550HeaderIDRange, id) } @@ -330,6 +358,7 @@ func (e *RawExtension) Unmarshal(buf []byte) (int, error) { return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2]) } e.payload = buf + return len(buf), nil } @@ -344,6 +373,7 @@ func (e RawExtension) MarshalTo(buf []byte) (int, error) { if size > len(buf) { return 0, io.ErrShortBuffer } + return copy(buf, e.payload), nil } diff --git a/header_extension_test.go b/header_extension_test.go index bac3bd0..f12362e 100644 --- a/header_extension_test.go +++ b/header_extension_test.go @@ -27,7 +27,7 @@ func TestHeaderExtension_RFC8285OneByteExtension(t *testing.T) { } func TestHeaderExtension_RFC8285OneByteTwoExtensionOfTwoBytes(t *testing.T) { - p := &OneByteHeaderExtension{} + ext := &OneByteHeaderExtension{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -39,30 +39,30 @@ func TestHeaderExtension_RFC8285OneByteTwoExtensionOfTwoBytes(t *testing.T) { rawPkt := []byte{ 0xBE, 0xDE, 0x00, 0x01, 0x10, 0xAA, 0x20, 0xBB, } - if _, err := p.Unmarshal(rawPkt); err != nil { + if _, err := ext.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.Get(1) + ext1 := ext.Get(1) ext1Expect := []byte{0xAA} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %+v, Expected: %+v", ext1, ext1Expect) } - ext2 := p.Get(2) + ext2 := ext.Get(2) ext2Expect := []byte{0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %+v, Expected: %+v", ext2, ext2Expect) } - dstData, _ := p.Marshal() + dstData, _ := ext.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } func TestHeaderExtension_RFC8285OneByteMultipleExtensionsWithPadding(t *testing.T) { - p := &OneByteHeaderExtension{} + ext := &OneByteHeaderExtension{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -79,23 +79,23 @@ func TestHeaderExtension_RFC8285OneByteMultipleExtensionsWithPadding(t *testing. 0xBE, 0xDE, 0x00, 0x03, 0x10, 0xAA, 0x21, 0xBB, 0xBB, 0x00, 0x00, 0x33, 0xCC, 0xCC, 0xCC, 0xCC, } - if _, err := p.Unmarshal(rawPkt); err != nil { + if _, err := ext.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.Get(1) + ext1 := ext.Get(1) ext1Expect := []byte{0xAA} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext1, ext1Expect) } - ext2 := p.Get(2) + ext2 := ext.Get(2) ext2Expect := []byte{0xBB, 0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext2, ext2Expect) } - ext3 := p.Get(3) + ext3 := ext.Get(3) ext3Expect := []byte{0xCC, 0xCC, 0xCC, 0xCC} if !bytes.Equal(ext3, ext3Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext3, ext3Expect) @@ -111,7 +111,7 @@ func TestHeaderExtension_RFC8285OneByteMultipleExtensionsWithPadding(t *testing. for name, buf := range dstBuf { buf := buf t.Run(name, func(t *testing.T) { - n, err := p.MarshalTo(buf) + n, err := ext.MarshalTo(buf) if err != nil { t.Fatal(err) } @@ -123,7 +123,7 @@ func TestHeaderExtension_RFC8285OneByteMultipleExtensionsWithPadding(t *testing. } func TestHeaderExtension_RFC8285TwoByteExtension(t *testing.T) { - p := &TwoByteHeaderExtension{} + ext := &TwoByteHeaderExtension{} rawPkt := []byte{ 0x10, 0x00, 0x00, 0x07, 0x05, 0x18, 0xAA, 0xAA, @@ -131,18 +131,18 @@ func TestHeaderExtension_RFC8285TwoByteExtension(t *testing.T) { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, } - if _, err := p.Unmarshal(rawPkt); err != nil { + if _, err := ext.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - dstData, _ := p.Marshal() + dstData, _ := ext.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithPadding(t *testing.T) { - p := &TwoByteHeaderExtension{} + ext := &TwoByteHeaderExtension{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -160,23 +160,23 @@ func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithPadding(t *testing. 0xBB, 0x00, 0x03, 0x04, 0xCC, 0xCC, 0xCC, 0xCC, } - if _, err := p.Unmarshal(rawPkt); err != nil { + if _, err := ext.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.Get(1) + ext1 := ext.Get(1) ext1Expect := []byte{} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext1, ext1Expect) } - ext2 := p.Get(2) + ext2 := ext.Get(2) ext2Expect := []byte{0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext2, ext2Expect) } - ext3 := p.Get(3) + ext3 := ext.Get(3) ext3Expect := []byte{0xCC, 0xCC, 0xCC, 0xCC} if !bytes.Equal(ext3, ext3Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext3, ext3Expect) @@ -184,7 +184,7 @@ func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithPadding(t *testing. } func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithLargeExtension(t *testing.T) { - p := &TwoByteHeaderExtension{} + ext := &TwoByteHeaderExtension{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -209,23 +209,23 @@ func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithLargeExtension(t *t 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, } - if _, err := p.Unmarshal(rawPkt); err != nil { + if _, err := ext.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.Get(1) + ext1 := ext.Get(1) ext1Expect := []byte{} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext1, ext1Expect) } - ext2 := p.Get(2) + ext2 := ext.Get(2) ext2Expect := []byte{0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext2, ext2Expect) } - ext3 := p.Get(3) + ext3 := ext.Get(3) ext3Expect := []byte{ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, @@ -234,71 +234,71 @@ func TestHeaderExtension_RFC8285TwoByteMultipleExtensionsWithLargeExtension(t *t t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext3, ext3Expect) } - dstData, _ := p.Marshal() + dstData, _ := ext.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled: %+v,\nrawPkt: %+v", dstData, rawPkt) } } func TestHeaderExtension_RFC8285OneByteDelExtension(t *testing.T) { - p := &OneByteHeaderExtension{} + ext := &OneByteHeaderExtension{} - if _, err := p.Unmarshal([]byte{0xBE, 0xDE, 0x00, 0x00}); err != nil { + if _, err := ext.Unmarshal([]byte{0xBE, 0xDE, 0x00, 0x00}); err != nil { t.Fatal("Unmarshal err for valid extension") } - if err := p.Set(1, []byte{0xBB}); err != nil { + if err := ext.Set(1, []byte{0xBB}); err != nil { t.Fatal("Set err for valid extension") } - ext := p.Get(1) - if ext == nil { + extExtension := ext.Get(1) + if extExtension == nil { t.Error("Extension should exist") } - err := p.Del(1) + err := ext.Del(1) if err != nil { t.Error("Should successfully delete extension") } - ext = p.Get(1) - if ext != nil { + extExtension = ext.Get(1) + if extExtension != nil { t.Error("Extension should not exist") } - err = p.Del(1) + err = ext.Del(1) if err == nil { t.Error("Should return error when deleting extension that doesnt exist") } } func TestHeaderExtension_RFC8285TwoByteDelExtension(t *testing.T) { - p := &TwoByteHeaderExtension{} + ext := &TwoByteHeaderExtension{} - if _, err := p.Unmarshal([]byte{0x10, 0x00, 0x00, 0x00}); err != nil { + if _, err := ext.Unmarshal([]byte{0x10, 0x00, 0x00, 0x00}); err != nil { t.Fatal("Unmarshal err for valid extension") } - if err := p.Set(1, []byte{0xBB}); err != nil { + if err := ext.Set(1, []byte{0xBB}); err != nil { t.Fatal("Set err for valid extension") } - ext := p.Get(1) - if ext == nil { + extExtension := ext.Get(1) + if extExtension == nil { t.Error("Extension should exist") } - err := p.Del(1) + err := ext.Del(1) if err != nil { t.Error("Should successfully delete extension") } - ext = p.Get(1) - if ext != nil { + extExtension = ext.Get(1) + if extExtension != nil { t.Error("Extension should not exist") } - err = p.Del(1) + err = ext.Del(1) if err == nil { t.Error("Should return error when deleting extension that doesnt exist") } diff --git a/packet.go b/packet.go index e74d48d..e2eaf1a 100644 --- a/packet.go +++ b/packet.go @@ -9,13 +9,13 @@ import ( "io" ) -// Extension RTP Header extension +// Extension RTP Header extension. type Extension struct { id uint8 payload []byte } -// Header represents an RTP packet header +// Header represents an RTP packet header. type Header struct { Version uint8 Padding bool @@ -33,7 +33,7 @@ type Header struct { PayloadOffset int } -// Packet represents an RTP Packet +// Packet represents an RTP Packet. type Packet struct { Header Payload []byte @@ -68,7 +68,7 @@ const ( csrcLength = 4 ) -// String helps with debugging by printing packet information in a readable way +// String helps with debugging by printing packet information in a readable way. func (p Packet) String() string { out := "RTP PACKET:\n" @@ -85,7 +85,7 @@ func (p Packet) String() string { // Unmarshal parses the passed byte slice and stores the result in the Header. // It returns the number of bytes read n and any error. -func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit +func (h *Header) Unmarshal(buf []byte) (n int, err error) { // nolint: funlen,gocognit,cyclop if len(buf) < headerLength { return 0, fmt.Errorf("%w: %d < %d", errHeaderSizeInsufficient, len(buf), headerLength) } @@ -137,7 +137,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit h.Extensions = h.Extensions[:0] } - if h.Extension { + if h.Extension { // nolint: nestif if expected := n + 4; len(buf) < expected { return n, fmt.Errorf("size %d < %d: %w", len(buf), expected, @@ -164,6 +164,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit for n < extensionEnd { if buf[n] == 0x00 { // padding n++ + continue } @@ -220,6 +221,8 @@ func (p *Packet) Unmarshal(buf []byte) error { } p.PaddingSize = buf[end-1] end -= int(p.PaddingSize) + } else { + p.PaddingSize = 0 } if end < n { return errTooSmall @@ -243,7 +246,7 @@ func (h Header) Marshal() (buf []byte, err error) { } // MarshalTo serializes the header and writes to the buffer. -func (h Header) MarshalTo(buf []byte) (n int, err error) { +func (h Header) MarshalTo(buf []byte) (n int, err error) { // nolint: funlen, cyclop /* * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -266,7 +269,7 @@ func (h Header) MarshalTo(buf []byte) (n int, err error) { // The first byte contains the version, padding bit, extension bit, // and csrc size. - buf[0] = (h.Version << versionShift) | uint8(len(h.CSRC)) + buf[0] = (h.Version << versionShift) | uint8(len(h.CSRC)) // nolint: gosec // G115 if h.Padding { buf[0] |= 1 << paddingShift } @@ -301,7 +304,7 @@ func (h Header) MarshalTo(buf []byte) (n int, err error) { // RFC 8285 RTP One Byte Header Extension case extensionProfileOneByte: for _, extension := range h.Extensions { - buf[n] = extension.id<<4 | (uint8(len(extension.payload)) - 1) + buf[n] = extension.id<<4 | (uint8(len(extension.payload)) - 1) // nolint: gosec // G115 n++ n += copy(buf[n:], extension.payload) } @@ -310,7 +313,7 @@ func (h Header) MarshalTo(buf []byte) (n int, err error) { for _, extension := range h.Extensions { buf[n] = extension.id n++ - buf[n] = uint8(len(extension.payload)) + buf[n] = uint8(len(extension.payload)) // nolint: gosec // G115 n++ n += copy(buf[n:], extension.payload) } @@ -327,6 +330,7 @@ func (h Header) MarshalTo(buf []byte) (n int, err error) { extSize := n - startExtensionsPos roundedExtSize := ((extSize + 3) / 4) * 4 + // nolint: gosec // G115 false positive binary.BigEndian.PutUint16(buf[extHeaderPos+2:extHeaderPos+4], uint16(roundedExtSize/4)) // add padding to reach 4 bytes boundaries @@ -369,9 +373,9 @@ func (h Header) MarshalSize() int { return size } -// SetExtension sets an RTP header extension -func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocognit - if h.Extension { +// SetExtension sets an RTP header extension. +func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocognit, cyclop + if h.Extension { // nolint: nestif switch h.ExtensionProfile { // RFC 8285 RTP One Byte Header Extension case extensionProfileOneByte: @@ -399,10 +403,13 @@ func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocogni for i, extension := range h.Extensions { if extension.id == id { h.Extensions[i].payload = payload + return nil } } + h.Extensions = append(h.Extensions, Extension{id: id, payload: payload}) + return nil } @@ -417,10 +424,11 @@ func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocogni } h.Extensions = append(h.Extensions, Extension{id: id, payload: payload}) + return nil } -// GetExtensionIDs returns an extension id array +// GetExtensionIDs returns an extension id array. func (h *Header) GetExtensionIDs() []uint8 { if !h.Extension { return nil @@ -434,10 +442,11 @@ func (h *Header) GetExtensionIDs() []uint8 { for _, extension := range h.Extensions { ids = append(ids, extension.id) } + return ids } -// GetExtension returns an RTP header extension +// GetExtension returns an RTP header extension. func (h *Header) GetExtension(id uint8) []byte { if !h.Extension { return nil @@ -447,10 +456,11 @@ func (h *Header) GetExtension(id uint8) []byte { return extension.payload } } + return nil } -// DelExtension Removes an RTP Header extension +// DelExtension Removes an RTP Header extension. func (h *Header) DelExtension(id uint8) error { if !h.Extension { return errHeaderExtensionsNotEnabled @@ -458,9 +468,11 @@ func (h *Header) DelExtension(id uint8) error { for i, extension := range h.Extensions { if extension.id == id { h.Extensions = append(h.Extensions[:i], h.Extensions[i+1:]...) + return nil } } + return errHeaderExtensionNotFound } @@ -515,6 +527,7 @@ func (p Packet) Clone() *Packet { copy(clone.Payload, p.Payload) } clone.PaddingSize = p.PaddingSize + return clone } @@ -536,5 +549,6 @@ func (h Header) Clone() Header { } clone.Extensions = ext } + return clone } diff --git a/packet_test.go b/packet_test.go index 98dfb40..0813ee0 100644 --- a/packet_test.go +++ b/packet_test.go @@ -12,10 +12,10 @@ import ( "testing" ) -func TestBasic(t *testing.T) { - p := &Packet{} +func TestBasic(t *testing.T) { // nolint:funlen,maintidx,cyclop + packet := &Packet{} - if err := p.Unmarshal([]byte{}); err == nil { + if err := packet.Unmarshal([]byte{}); err == nil { t.Fatal("Unmarshal did not error on zero length packet") } @@ -48,10 +48,10 @@ func TestBasic(t *testing.T) { // Unmarshal to the used Packet should work as well. for i := 0; i < 2; i++ { t.Run(fmt.Sprintf("Run%d", i+1), func(t *testing.T) { - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Error(err) - } else if !reflect.DeepEqual(p, parsedPacket) { - t.Errorf("TestBasic unmarshal: got %#v, want %#v", p, parsedPacket) + } else if !reflect.DeepEqual(packet, parsedPacket) { + t.Errorf("TestBasic unmarshal: got %#v, want %#v", packet, parsedPacket) } if parsedPacket.Header.MarshalSize() != 20 { @@ -60,7 +60,7 @@ func TestBasic(t *testing.T) { t.Errorf("wrong computed marshal size") } - raw, err := p.Marshal() + raw, err := packet.Marshal() if err != nil { t.Error(err) } else if !reflect.DeepEqual(raw, rawPkt) { @@ -95,10 +95,42 @@ func TestBasic(t *testing.T) { Payload: rawPkt[20:21], PaddingSize: 4, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Error(err) - } else if !reflect.DeepEqual(p, parsedPacket) { - t.Errorf("TestBasic padding unmarshal: got %#v, want %#v", p, parsedPacket) + } else if !reflect.DeepEqual(packet, parsedPacket) { + t.Errorf("TestBasic padding unmarshal: got %#v, want %#v", packet, parsedPacket) + } + + // packet with zero padding following packet with non-zero padding + rawPkt = []byte{ + 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, + 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e, + } + parsedPacket = &Packet{ + Header: Header{ + Padding: false, + Marker: true, + Extension: true, + ExtensionProfile: 1, + Extensions: []Extension{ + {0, []byte{ + 0xFF, 0xFF, 0xFF, 0xFF, + }}, + }, + Version: 2, + PayloadType: 96, + SequenceNumber: 27023, + Timestamp: 3653407706, + SSRC: 476325762, + CSRC: []uint32{}, + }, + Payload: rawPkt[20:], + PaddingSize: 0, + } + if err := packet.Unmarshal(rawPkt); err != nil { + t.Error(err) + } else if !reflect.DeepEqual(packet, parsedPacket) { + t.Errorf("TestBasic zero padding unmarshal: got %#v, want %#v", packet, parsedPacket) } // packet with only padding @@ -127,13 +159,13 @@ func TestBasic(t *testing.T) { Payload: []byte{}, PaddingSize: 5, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Error(err) - } else if !reflect.DeepEqual(p, parsedPacket) { - t.Errorf("TestBasic padding only unmarshal: got %#v, want %#v", p, parsedPacket) + } else if !reflect.DeepEqual(packet, parsedPacket) { + t.Errorf("TestBasic padding only unmarshal: got %#v, want %#v", packet, parsedPacket) } - if len(p.Payload) != 0 { - t.Errorf("Unmarshal of padding only packet has payload of non-zero length: %d", len(p.Payload)) + if len(packet.Payload) != 0 { + t.Errorf("Unmarshal of padding only packet has payload of non-zero length: %d", len(packet.Payload)) } // packet with excessive padding @@ -162,7 +194,7 @@ func TestBasic(t *testing.T) { Payload: []byte{}, PaddingSize: 0, } - err := p.Unmarshal(rawPkt) + err := packet.Unmarshal(rawPkt) if err == nil { t.Fatal("Unmarshal did not error on packet with excessive padding") } @@ -274,13 +306,13 @@ func TestBasic(t *testing.T) { } func TestExtension(t *testing.T) { - p := &Packet{} + packet := &Packet{} missingExtensionPkt := []byte{ 0x90, 0x60, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, } - if err := p.Unmarshal(missingExtensionPkt); err == nil { + if err := packet.Unmarshal(missingExtensionPkt); err == nil { t.Fatal("Unmarshal did not error on packet with missing extension data") } @@ -288,11 +320,11 @@ func TestExtension(t *testing.T) { 0x90, 0x60, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0x99, 0x99, 0x99, 0x99, } - if err := p.Unmarshal(invalidExtensionLengthPkt); err == nil { + if err := packet.Unmarshal(invalidExtensionLengthPkt); err == nil { t.Fatal("Unmarshal did not error on packet with invalid extension length") } - p = &Packet{ + packet = &Packet{ Header: Header{ Extension: true, ExtensionProfile: 3, @@ -304,24 +336,24 @@ func TestExtension(t *testing.T) { }, Payload: []byte{}, } - if _, err := p.Marshal(); err == nil { + if _, err := packet.Marshal(); err == nil { t.Fatal("Marshal did not error on packet with invalid extension length") } } func TestRFC8285OneByteExtension(t *testing.T) { - p := &Packet{} + packet := &Packet{} rawPkt := []byte{ 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00, 0x01, 0x50, 0xAA, 0x00, 0x00, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - p = &Packet{ + packet = &Packet{ Header: Header{ Marker: true, Extension: true, @@ -341,14 +373,14 @@ func TestRFC8285OneByteExtension(t *testing.T) { Payload: rawPkt[20:], } - dstData, _ := p.Marshal() + dstData, _ := packet.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } func TestRFC8285OneByteTwoExtensionOfTwoBytes(t *testing.T) { - p := &Packet{} + packet := &Packet{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -363,24 +395,24 @@ func TestRFC8285OneByteTwoExtensionOfTwoBytes(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.GetExtension(1) + ext1 := packet.GetExtension(1) ext1Expect := []byte{0xAA} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %+v, Expected: %+v", ext1, ext1Expect) } - ext2 := p.GetExtension(2) + ext2 := packet.GetExtension(2) ext2Expect := []byte{0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %+v, Expected: %+v", ext2, ext2Expect) } // Test Marshal - p = &Packet{ + packet = &Packet{ Header: Header{ Marker: true, Extension: true, @@ -403,14 +435,14 @@ func TestRFC8285OneByteTwoExtensionOfTwoBytes(t *testing.T) { Payload: rawPkt[20:], } - dstData, _ := p.Marshal() + dstData, _ := packet.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } -func TestRFC8285OneByteMultipleExtensionsWithPadding(t *testing.T) { - p := &Packet{} +func TestRFC8285OneByteMultipleExtensionsWithPadding(t *testing.T) { // nolint:funlen + packet := &Packet{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -430,23 +462,23 @@ func TestRFC8285OneByteMultipleExtensionsWithPadding(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.GetExtension(1) + ext1 := packet.GetExtension(1) ext1Expect := []byte{0xAA} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext1, ext1Expect) } - ext2 := p.GetExtension(2) + ext2 := packet.GetExtension(2) ext2Expect := []byte{0xBB, 0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext2, ext2Expect) } - ext3 := p.GetExtension(3) + ext3 := packet.GetExtension(3) ext3Expect := []byte{0xCC, 0xCC, 0xCC, 0xCC} if !bytes.Equal(ext3, ext3Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext3, ext3Expect) @@ -469,7 +501,7 @@ func TestRFC8285OneByteMultipleExtensionsWithPadding(t *testing.T) { for name, buf := range dstBuf { buf := buf t.Run(name, func(t *testing.T) { - n, err := p.MarshalTo(buf) + n, err := packet.MarshalTo(buf) if err != nil { t.Fatal(err) } @@ -500,7 +532,7 @@ func TestRFC8285OneByteMultipleExtensions(t *testing.T) { 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -526,14 +558,14 @@ func TestRFC8285OneByteMultipleExtensions(t *testing.T) { Payload: rawPkt[28:], } - dstData, _ := p.Marshal() + dstData, _ := packet.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } func TestRFC8285TwoByteExtension(t *testing.T) { - p := &Packet{} + packet := &Packet{} rawPkt := []byte{ 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, @@ -542,11 +574,11 @@ func TestRFC8285TwoByteExtension(t *testing.T) { 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x00, 0x00, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - p = &Packet{ + packet = &Packet{ Header: Header{ Marker: true, Extension: true, @@ -568,14 +600,14 @@ func TestRFC8285TwoByteExtension(t *testing.T) { Payload: rawPkt[44:], } - dstData, _ := p.Marshal() + dstData, _ := packet.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled:\n%s\nrawPkt:\n%s", hex.Dump(dstData), hex.Dump(rawPkt)) } } func TestRFC8285TwoByteMultipleExtensionsWithPadding(t *testing.T) { - p := &Packet{} + packet := &Packet{} // 0 1 2 3 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 @@ -594,23 +626,23 @@ func TestRFC8285TwoByteMultipleExtensionsWithPadding(t *testing.T) { 0xBB, 0x00, 0x03, 0x04, 0xCC, 0xCC, 0xCC, 0xCC, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal("Unmarshal err for valid extension") } - ext1 := p.GetExtension(1) + ext1 := packet.GetExtension(1) ext1Expect := []byte{} if !bytes.Equal(ext1, ext1Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext1, ext1Expect) } - ext2 := p.GetExtension(2) + ext2 := packet.GetExtension(2) ext2Expect := []byte{0xBB} if !bytes.Equal(ext2, ext2Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext2, ext2Expect) } - ext3 := p.GetExtension(3) + ext3 := packet.GetExtension(3) ext3Expect := []byte{0xCC, 0xCC, 0xCC, 0xCC} if !bytes.Equal(ext3, ext3Expect) { t.Errorf("Extension has incorrect data. Got: %v+, Expected: %v+", ext3, ext3Expect) @@ -644,7 +676,7 @@ func TestRFC8285TwoByteMultipleExtensionsWithLargeExtension(t *testing.T) { 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -669,7 +701,7 @@ func TestRFC8285TwoByteMultipleExtensionsWithLargeExtension(t *testing.T) { Payload: rawPkt[40:], } - dstData, _ := p.Marshal() + dstData, _ := packet.Marshal() if !bytes.Equal(dstData, rawPkt) { t.Errorf("Marshal failed raw \nMarshaled: %+v,\nrawPkt: %+v", dstData, rawPkt) } @@ -680,7 +712,7 @@ func TestRFC8285GetExtensionReturnsNilWhenExtensionsDisabled(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -694,7 +726,7 @@ func TestRFC8285GetExtensionReturnsNilWhenExtensionsDisabled(t *testing.T) { Payload: payload, } - err := p.GetExtension(1) + err := packet.GetExtension(1) if err != nil { t.Error("Should return nil on GetExtension when h.Extension: false") } @@ -705,7 +737,7 @@ func TestRFC8285DelExtension(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -725,22 +757,22 @@ func TestRFC8285DelExtension(t *testing.T) { Payload: payload, } - ext := p.GetExtension(1) + ext := packet.GetExtension(1) if ext == nil { t.Error("Extension should exist") } - err := p.DelExtension(1) + err := packet.DelExtension(1) if err != nil { t.Error("Should successfully delete extension") } - ext = p.GetExtension(1) + ext = packet.GetExtension(1) if ext != nil { t.Error("Extension should not exist") } - err = p.DelExtension(1) + err = packet.DelExtension(1) if err == nil { t.Error("Should return error when deleting extension that doesnt exist") } @@ -751,7 +783,7 @@ func TestRFC8285GetExtensionIDs(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -774,16 +806,20 @@ func TestRFC8285GetExtensionIDs(t *testing.T) { Payload: payload, } - ids := p.GetExtensionIDs() + ids := packet.GetExtensionIDs() if ids == nil { t.Error("Extension should exist") } - if len(ids) != len(p.Extensions) { - t.Errorf("The number of IDs should be equal to the number of extensions,want=%d,have=%d", len(p.Extensions), len(ids)) + if len(ids) != len(packet.Extensions) { + t.Errorf( + "The number of IDs should be equal to the number of extensions,want=%d,have=%d", + len(packet.Extensions), + len(ids), + ) } for _, id := range ids { - ext := p.GetExtension(id) + ext := packet.GetExtension(id) if ext == nil { t.Error("Extension should exist") } @@ -795,7 +831,7 @@ func TestRFC8285GetExtensionIDsReturnsErrorWhenExtensionsDisabled(t *testing.T) // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -809,7 +845,7 @@ func TestRFC8285GetExtensionIDsReturnsErrorWhenExtensionsDisabled(t *testing.T) Payload: payload, } - ids := p.GetExtensionIDs() + ids := packet.GetExtensionIDs() if ids != nil { t.Error("Should return nil on GetExtensionIDs when h.Extensions is nil") } @@ -820,7 +856,7 @@ func TestRFC8285DelExtensionReturnsErrorWhenExtensionsDisabled(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -834,7 +870,7 @@ func TestRFC8285DelExtensionReturnsErrorWhenExtensionsDisabled(t *testing.T) { Payload: payload, } - err := p.DelExtension(1) + err := packet.DelExtension(1) if err == nil { t.Error("Should return error on DelExtension when h.Extension: false") } @@ -845,7 +881,7 @@ func TestRFC8285OneByteSetExtensionShouldEnableExensionsWhenAdding(t *testing.T) // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -860,24 +896,24 @@ func TestRFC8285OneByteSetExtensionShouldEnableExensionsWhenAdding(t *testing.T) } extension := []byte{0xAA, 0xAA} - err := p.SetExtension(1, extension) + err := packet.SetExtension(1, extension) if err != nil { t.Error("Error setting extension") } - if p.Extension != true { + if packet.Extension != true { t.Error("Extension should be set to true") } - if p.ExtensionProfile != 0xBEDE { + if packet.ExtensionProfile != 0xBEDE { t.Error("Extension profile should be set to 0xBEDE") } - if len(p.Extensions) != 1 { + if len(packet.Extensions) != 1 { t.Error("Extensions should be set to 1") } - if !bytes.Equal(p.GetExtension(1), extension) { + if !bytes.Equal(packet.GetExtension(1), extension) { t.Error("Extension value is not set") } } @@ -887,7 +923,7 @@ func TestRFC8285OneByteSetExtensionShouldSetCorrectExtensionProfileFor16ByteExte // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -907,12 +943,12 @@ func TestRFC8285OneByteSetExtensionShouldSetCorrectExtensionProfileFor16ByteExte 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, } - err := p.SetExtension(1, extension) + err := packet.SetExtension(1, extension) if err != nil { t.Error("Error setting extension") } - if p.ExtensionProfile != 0xBEDE { + if packet.ExtensionProfile != 0xBEDE { t.Error("Extension profile should be set to 0xBEDE") } } @@ -922,7 +958,7 @@ func TestRFC8285OneByteSetExtensionShouldUpdateExistingExension(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -942,17 +978,17 @@ func TestRFC8285OneByteSetExtensionShouldUpdateExistingExension(t *testing.T) { Payload: payload, } - if !bytes.Equal(p.GetExtension(1), []byte{0xAA}) { + if !bytes.Equal(packet.GetExtension(1), []byte{0xAA}) { t.Error("Extension value not initialize properly") } extension := []byte{0xBB} - err := p.SetExtension(1, extension) + err := packet.SetExtension(1, extension) if err != nil { t.Error("Error setting extension") } - if !bytes.Equal(p.GetExtension(1), extension) { + if !bytes.Equal(packet.GetExtension(1), extension) { t.Error("Extension value was not set") } } @@ -962,7 +998,7 @@ func TestRFC8285OneByteSetExtensionShouldErrorWhenInvalidIDProvided(t *testing.T // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -982,34 +1018,34 @@ func TestRFC8285OneByteSetExtensionShouldErrorWhenInvalidIDProvided(t *testing.T Payload: payload, } - if p.SetExtension(0, []byte{0xBB}) == nil { + if packet.SetExtension(0, []byte{0xBB}) == nil { t.Error("SetExtension did not error on invalid id") } - if p.SetExtension(15, []byte{0xBB}) == nil { + if packet.SetExtension(15, []byte{0xBB}) == nil { t.Error("SetExtension did not error on invalid id") } } func TestRFC8285OneByteExtensionTermianteProcessingWhenReservedIDEncountered(t *testing.T) { - p := &Packet{} + packet := &Packet{} reservedIDPkt := []byte{ 0x90, 0xe0, 0x69, 0x8f, 0xd9, 0xc2, 0x93, 0xda, 0x1c, 0x64, 0x27, 0x82, 0xBE, 0xDE, 0x00, 0x01, 0xF0, 0xAA, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - if err := p.Unmarshal(reservedIDPkt); err != nil { + if err := packet.Unmarshal(reservedIDPkt); err != nil { t.Error("Unmarshal error on packet with reserved extension id") } - if len(p.Extensions) != 0 { + if len(packet.Extensions) != 0 { t.Error("Extensions should be empty for invalid id") } payload := reservedIDPkt[17:] - if !bytes.Equal(p.Payload, payload) { + if !bytes.Equal(packet.Payload, payload) { t.Errorf("p.Payload must be same as payload.\n p.Payload: %+v,\n payload: %+v", - p.Payload, payload, + packet.Payload, payload, ) } } @@ -1019,7 +1055,7 @@ func TestRFC8285OneByteSetExtensionShouldErrorWhenPayloadTooLarge(t *testing.T) // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -1039,7 +1075,7 @@ func TestRFC8285OneByteSetExtensionShouldErrorWhenPayloadTooLarge(t *testing.T) Payload: payload, } - if p.SetExtension(1, []byte{ + if packet.SetExtension(1, []byte{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, }) == nil { @@ -1052,7 +1088,7 @@ func TestRFC8285TwoByteSetExtensionShouldEnableExensionsWhenAdding(t *testing.T) // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: false, @@ -1070,24 +1106,24 @@ func TestRFC8285TwoByteSetExtensionShouldEnableExensionsWhenAdding(t *testing.T) 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, } - err := p.SetExtension(1, extension) + err := packet.SetExtension(1, extension) if err != nil { t.Error("Error setting extension") } - if p.Extension != true { + if packet.Extension != true { t.Error("Extension should be set to true") } - if p.ExtensionProfile != 0x1000 { + if packet.ExtensionProfile != 0x1000 { t.Error("Extension profile should be set to 0xBEDE") } - if len(p.Extensions) != 1 { + if len(packet.Extensions) != 1 { t.Error("Extensions should be set to 1") } - if !bytes.Equal(p.GetExtension(1), extension) { + if !bytes.Equal(packet.GetExtension(1), extension) { t.Error("Extension value is not set") } } @@ -1097,7 +1133,7 @@ func TestRFC8285TwoByteSetExtensionShouldUpdateExistingExension(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -1117,7 +1153,7 @@ func TestRFC8285TwoByteSetExtensionShouldUpdateExistingExension(t *testing.T) { Payload: payload, } - if !bytes.Equal(p.GetExtension(1), []byte{0xAA}) { + if !bytes.Equal(packet.GetExtension(1), []byte{0xAA}) { t.Error("Extension value not initialize properly") } @@ -1125,12 +1161,12 @@ func TestRFC8285TwoByteSetExtensionShouldUpdateExistingExension(t *testing.T) { 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, } - err := p.SetExtension(1, extension) + err := packet.SetExtension(1, extension) if err != nil { t.Error("Error setting extension") } - if !bytes.Equal(p.GetExtension(1), extension) { + if !bytes.Equal(packet.GetExtension(1), extension) { t.Error("Extension value was not set") } } @@ -1140,7 +1176,7 @@ func TestRFC8285TwoByteSetExtensionShouldErrorWhenPayloadTooLarge(t *testing.T) // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -1160,7 +1196,7 @@ func TestRFC8285TwoByteSetExtensionShouldErrorWhenPayloadTooLarge(t *testing.T) Payload: payload, } - if p.SetExtension(1, []byte{ + if packet.SetExtension(1, []byte{ 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, 0xBB, @@ -1225,7 +1261,7 @@ func TestRFC3550SetExtensionShouldErrorWhenNonZero(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -1246,11 +1282,11 @@ func TestRFC3550SetExtensionShouldErrorWhenNonZero(t *testing.T) { } expect := []byte{0xBB} - if p.SetExtension(0, expect) != nil { + if packet.SetExtension(0, expect) != nil { t.Error("SetExtension should not error on valid id") } - actual := p.GetExtension(0) + actual := packet.GetExtension(0) if !bytes.Equal(actual, expect) { t.Error("p.GetExtension returned incorrect value.") } @@ -1261,7 +1297,7 @@ func TestRFC3550SetExtensionShouldRaiseErrorWhenSettingNonzeroID(t *testing.T) { // Payload 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Header: Header{ Marker: true, Extension: true, @@ -1276,7 +1312,7 @@ func TestRFC3550SetExtensionShouldRaiseErrorWhenSettingNonzeroID(t *testing.T) { Payload: payload, } - if p.SetExtension(1, []byte{0xBB}) == nil { + if packet.SetExtension(1, []byte{0xBB}) == nil { t.Error("SetExtension did not error on invalid id") } } @@ -1350,32 +1386,32 @@ func TestRoundtrip(t *testing.T) { } payload := rawPkt[12:] - p := &Packet{} - if err := p.Unmarshal(rawPkt); err != nil { + packet := &Packet{} + if err := packet.Unmarshal(rawPkt); err != nil { t.Fatal(err) } - if !bytes.Equal(payload, p.Payload) { + if !bytes.Equal(payload, packet.Payload) { t.Errorf("p.Payload must be same as payload.\n payload: %+v,\np.Payload: %+v", - payload, p.Payload, + payload, packet.Payload, ) } - buf, err := p.Marshal() + buf, err := packet.Marshal() if err != nil { t.Fatal(err) } if !bytes.Equal(rawPkt, buf) { t.Errorf("buf must be same as rawPkt.\n buf: %+v,\nrawPkt: %+v", buf, rawPkt) } - if !bytes.Equal(payload, p.Payload) { + if !bytes.Equal(payload, packet.Payload) { t.Errorf("p.Payload must be same as payload.\n payload: %+v,\np.Payload: %+v", - payload, p.Payload, + payload, packet.Payload, ) } } func TestCloneHeader(t *testing.T) { - h := Header{ + header := Header{ Marker: true, Extension: true, ExtensionProfile: 1, @@ -1391,16 +1427,16 @@ func TestCloneHeader(t *testing.T) { SSRC: 476325762, CSRC: []uint32{}, } - clone := h.Clone() - if !reflect.DeepEqual(h, clone) { + clone := header.Clone() + if !reflect.DeepEqual(header, clone) { t.Errorf("Cloned clone does not match the original") } - h.CSRC = append(h.CSRC, 1) - if len(clone.CSRC) == len(h.CSRC) { + header.CSRC = append(header.CSRC, 1) + if len(clone.CSRC) == len(header.CSRC) { t.Errorf("Expected CSRC to be unchanged") } - h.Extensions[0].payload[0] = 0x1F + header.Extensions[0].payload[0] = 0x1F if clone.Extensions[0].payload[0] == 0x1F { t.Errorf("Expected Extensions to be unchanged") } @@ -1412,16 +1448,16 @@ func TestClonePacket(t *testing.T) { 0x27, 0x82, 0xBE, 0xDE, 0x00, 0x01, 0x50, 0xAA, 0x00, 0x00, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{ + packet := &Packet{ Payload: rawPkt[20:], } - clone := p.Clone() - if !reflect.DeepEqual(p, clone) { + clone := packet.Clone() + if !reflect.DeepEqual(packet, clone) { t.Errorf("Cloned Packet does not match the original") } - p.Payload[0] = 0x1F + packet.Payload[0] = 0x1F if clone.Payload[0] == 0x1F { t.Errorf("Expected Payload to be unchanged") } @@ -1433,8 +1469,8 @@ func BenchmarkMarshal(b *testing.B) { 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{} - err := p.Unmarshal(rawPkt) + packet := &Packet{} + err := packet.Unmarshal(rawPkt) if err != nil { b.Fatal(err) } @@ -1442,7 +1478,7 @@ func BenchmarkMarshal(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err = p.Marshal() + _, err = packet.Marshal() if err != nil { b.Fatal(err) } @@ -1455,9 +1491,9 @@ func BenchmarkMarshalTo(b *testing.B) { 0x27, 0x82, 0x00, 0x01, 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0x98, 0x36, 0xbe, 0x88, 0x9e, } - p := &Packet{} + packet := &Packet{} - err := p.Unmarshal(rawPkt) + err := packet.Unmarshal(rawPkt) if err != nil { b.Fatal(err) } @@ -1467,7 +1503,7 @@ func BenchmarkMarshalTo(b *testing.B) { b.ResetTimer() for i := 0; i < b.N; i++ { - _, err = p.MarshalTo(buf[:]) + _, err = packet.MarshalTo(buf[:]) if err != nil { b.Fatal(err) } @@ -1495,12 +1531,12 @@ func BenchmarkUnmarshal(b *testing.B) { } b.Run("SharedStruct", func(b *testing.B) { - p := &Packet{} + packet := &Packet{} b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - if err := p.Unmarshal(rawPkt); err != nil { + if err := packet.Unmarshal(rawPkt); err != nil { b.Fatal(err) } } @@ -1509,8 +1545,8 @@ func BenchmarkUnmarshal(b *testing.B) { b.ReportAllocs() b.ResetTimer() for i := 0; i < b.N; i++ { - p := &Packet{} - if err := p.Unmarshal(rawPkt); err != nil { + packet := &Packet{} + if err := packet.Unmarshal(rawPkt); err != nil { b.Fatal(err) } } diff --git a/packetizer.go b/packetizer.go index 7a6a46d..9ad07e0 100644 --- a/packetizer.go +++ b/packetizer.go @@ -7,12 +7,12 @@ import ( "time" ) -// Payloader payloads a byte array for use as rtp.Packet payloads +// Payloader payloads a byte array for use as rtp.Packet payloads. type Payloader interface { Payload(mtu uint16, payload []byte) [][]byte } -// Packetizer packetizes a payload +// Packetizer packetizes a payload. type Packetizer interface { Packetize(payload []byte, samples uint32) []*Packet GeneratePadding(samples uint32) []*Packet @@ -31,14 +31,22 @@ type packetizer struct { // Deprecated: will be removed in a future version. ClockRate uint32 - extensionNumbers struct { // put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number) + // put extension numbers in here. If they're 0, the extension is disabled (0 is not a legal extension number) + extensionNumbers struct { AbsSendTime int // http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time } timegen func() time.Time } -// NewPacketizer returns a new instance of a Packetizer for a specific payloader -func NewPacketizer(mtu uint16, pt uint8, ssrc uint32, payloader Payloader, sequencer Sequencer, clockRate uint32) Packetizer { +// NewPacketizer returns a new instance of a Packetizer for a specific payloader. +func NewPacketizer( + mtu uint16, + pt uint8, + ssrc uint32, + payloader Payloader, + sequencer Sequencer, + clockRate uint32, +) Packetizer { return &packetizer{ MTU: mtu, PayloadType: pt, @@ -55,7 +63,7 @@ func (p *packetizer) EnableAbsSendTime(value int) { p.extensionNumbers.AbsSendTime = value } -// Packetize packetizes the payload of an RTP packet and returns one or more RTP packets +// Packetize packetizes the payload of an RTP packet and returns one or more RTP packets. func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet { // Guard against an empty payload if len(payload) == 0 { @@ -90,7 +98,7 @@ func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet { if err != nil { return nil // never happens } - err = packets[len(packets)-1].SetExtension(uint8(p.extensionNumbers.AbsSendTime), b) + err = packets[len(packets)-1].SetExtension(uint8(p.extensionNumbers.AbsSendTime), b) // nolint: gosec // G115 if err != nil { return nil // never happens } @@ -99,7 +107,7 @@ func (p *packetizer) Packetize(payload []byte, samples uint32) []*Packet { return packets } -// GeneratePadding returns required padding-only packages +// GeneratePadding returns required padding-only packages. func (p *packetizer) GeneratePadding(samples uint32) []*Packet { // Guard against an empty payload if samples == 0 { @@ -132,7 +140,7 @@ func (p *packetizer) GeneratePadding(samples uint32) []*Packet { } // SkipSamples causes a gap in sample count between Packetize requests so the -// RTP payloads produced have a gap in timestamps +// RTP payloads produced have a gap in timestamps. func (p *packetizer) SkipSamples(skippedSamples uint32) { p.Timestamp += skippedSamples } diff --git a/packetizer_test.go b/packetizer_test.go index 78f8220..2842a05 100644 --- a/packetizer_test.go +++ b/packetizer_test.go @@ -75,7 +75,7 @@ func TestPacketizer_AbsSendTime(t *testing.T) { } } -func TestPacketizer_Roundtrip(t *testing.T) { +func TestPacketizer_Roundtrip(t *testing.T) { // nolint:funlen, cyclop multiplepayload := make([]byte, 128) packetizer := NewPacketizer(100, 98, 0x1234ABCD, &codecs.G722Payloader{}, NewRandomSequencer(), 90000) packets := packetizer.Packetize(multiplepayload, 1000) diff --git a/partitionheadchecker.go b/partitionheadchecker.go index 6f05aa5..51f16a9 100644 --- a/partitionheadchecker.go +++ b/partitionheadchecker.go @@ -3,7 +3,7 @@ package rtp -// PartitionHeadChecker is the interface that checks whether the packet is keyframe or not +// PartitionHeadChecker is the interface that checks whether the packet is keyframe or not. type PartitionHeadChecker interface { IsPartitionHead([]byte) bool } diff --git a/playoutdelayextension.go b/playoutdelayextension.go index 3882731..81d2d5b 100644 --- a/playoutdelayextension.go +++ b/playoutdelayextension.go @@ -22,29 +22,31 @@ var errPlayoutDelayInvalidValue = errors.New("invalid playout delay value") // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | len=2 | MIN delay | MAX delay | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . type PlayoutDelayExtension struct { - minDelay, maxDelay uint16 + MinDelay, MaxDelay uint16 } -// Marshal serializes the members to buffer +// Marshal serializes the members to buffer. func (p PlayoutDelayExtension) Marshal() ([]byte, error) { - if p.minDelay > playoutDelayMaxValue || p.maxDelay > playoutDelayMaxValue { + if p.MinDelay > playoutDelayMaxValue || p.MaxDelay > playoutDelayMaxValue { return nil, errPlayoutDelayInvalidValue } return []byte{ - byte(p.minDelay >> 4), - byte(p.minDelay<<4) | byte(p.maxDelay>>8), - byte(p.maxDelay), + byte(p.MinDelay >> 4), + byte(p.MinDelay<<4) | byte(p.MaxDelay>>8), + byte(p.MaxDelay), }, nil } -// Unmarshal parses the passed byte slice and stores the result in the members +// Unmarshal parses the passed byte slice and stores the result in the members. func (p *PlayoutDelayExtension) Unmarshal(rawData []byte) error { if len(rawData) < playoutDelayExtensionSize { return errTooSmall } - p.minDelay = binary.BigEndian.Uint16(rawData[0:2]) >> 4 - p.maxDelay = binary.BigEndian.Uint16(rawData[1:3]) & 0x0FFF + p.MinDelay = binary.BigEndian.Uint16(rawData[0:2]) >> 4 + p.MaxDelay = binary.BigEndian.Uint16(rawData[1:3]) & 0x0FFF + return nil } diff --git a/playoutdelayextension_test.go b/playoutdelayextension_test.go index 8810466..b08cbdb 100644 --- a/playoutdelayextension_test.go +++ b/playoutdelayextension_test.go @@ -20,7 +20,7 @@ func TestPlayoutDelayExtensionTooSmall(t *testing.T) { } func TestPlayoutDelayExtensionTooLarge(t *testing.T) { - t1 := PlayoutDelayExtension{minDelay: 1 << 12, maxDelay: 1 << 12} + t1 := PlayoutDelayExtension{MinDelay: 1 << 12, MaxDelay: 1 << 12} if _, err := t1.Marshal(); !errors.Is(err, errPlayoutDelayInvalidValue) { t.Fatal("err != errPlayoutDelayInvalidValue") @@ -39,7 +39,7 @@ func TestPlayoutDelayExtension(t *testing.T) { } t2 := PlayoutDelayExtension{ - minDelay: 1 << 4, maxDelay: 1 << 8, + MinDelay: 1 << 4, MaxDelay: 1 << 8, } if t1 != t2 { @@ -64,7 +64,7 @@ func TestPlayoutDelayExtensionExtraBytes(t *testing.T) { } t2 := PlayoutDelayExtension{ - minDelay: 1 << 4, maxDelay: 1 << 8, + MinDelay: 1 << 4, MaxDelay: 1 << 8, } if t1 != t2 { diff --git a/sequencer.go b/sequencer.go index 7aa7daa..aad5002 100644 --- a/sequencer.go +++ b/sequencer.go @@ -7,7 +7,7 @@ import ( "sync" ) -// Sequencer generates sequential sequence numbers for building RTP packets +// Sequencer generates sequential sequence numbers for building RTP packets. type Sequencer interface { NextSequenceNumber() uint16 RollOverCount() uint64 @@ -21,15 +21,15 @@ type Sequencer interface { const maxInitialRandomSequenceNumber = 1<<15 - 1 // NewRandomSequencer returns a new sequencer starting from a random sequence -// number +// number. func NewRandomSequencer() Sequencer { return &sequencer{ - sequenceNumber: uint16(globalMathRandomGenerator.Intn(maxInitialRandomSequenceNumber)), + sequenceNumber: uint16(globalMathRandomGenerator.Intn(maxInitialRandomSequenceNumber)), // nolint: gosec // G115 } } // NewFixedSequencer returns a new sequencer starting from a specific -// sequence number +// sequence number. func NewFixedSequencer(s uint16) Sequencer { return &sequencer{ sequenceNumber: s - 1, // -1 because the first sequence number prepends 1 @@ -43,7 +43,7 @@ type sequencer struct { } // NextSequenceNumber increment and returns a new sequence number for -// building RTP packets +// building RTP packets. func (s *sequencer) NextSequenceNumber() uint16 { s.mutex.Lock() defer s.mutex.Unlock() @@ -57,7 +57,7 @@ func (s *sequencer) NextSequenceNumber() uint16 { } // RollOverCount returns the amount of times the 16bit sequence number -// has wrapped +// has wrapped. func (s *sequencer) RollOverCount() uint64 { s.mutex.Lock() defer s.mutex.Unlock() diff --git a/transportccextension.go b/transportccextension.go index c2a998c..add44ea 100644 --- a/transportccextension.go +++ b/transportccextension.go @@ -8,7 +8,7 @@ import ( ) const ( - // transport-wide sequence + // transport-wide sequence. transportCCExtensionSize = 2 ) @@ -21,22 +21,25 @@ const ( // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ // | ID | L=1 |transport-wide sequence number | zero padding | // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// . type TransportCCExtension struct { TransportSequence uint16 } -// Marshal serializes the members to buffer +// Marshal serializes the members to buffer. func (t TransportCCExtension) Marshal() ([]byte, error) { buf := make([]byte, transportCCExtensionSize) binary.BigEndian.PutUint16(buf[0:2], t.TransportSequence) + return buf, nil } -// Unmarshal parses the passed byte slice and stores the result in the members +// Unmarshal parses the passed byte slice and stores the result in the members. func (t *TransportCCExtension) Unmarshal(rawData []byte) error { if len(rawData) < transportCCExtensionSize { return errTooSmall } t.TransportSequence = binary.BigEndian.Uint16(rawData[0:2]) + return nil } diff --git a/vlaextension.go b/vlaextension.go index e10820a..8863029 100644 --- a/vlaextension.go +++ b/vlaextension.go @@ -13,12 +13,18 @@ import ( ) var ( - ErrVLATooShort = errors.New("VLA payload too short") // ErrVLATooShort is returned when payload is too short - ErrVLAInvalidStreamCount = errors.New("invalid RTP stream count in VLA") // ErrVLAInvalidStreamCount is returned when RTP stream count is invalid - ErrVLAInvalidStreamID = errors.New("invalid RTP stream ID in VLA") // ErrVLAInvalidStreamID is returned when RTP stream ID is invalid - ErrVLAInvalidSpatialID = errors.New("invalid spatial ID in VLA") // ErrVLAInvalidSpatialID is returned when spatial ID is invalid - ErrVLADuplicateSpatialID = errors.New("duplicate spatial ID in VLA") // ErrVLADuplicateSpatialID is returned when spatial ID is invalid - ErrVLAInvalidTemporalLayer = errors.New("invalid temporal layer in VLA") // ErrVLAInvalidTemporalLayer is returned when temporal layer is invalid + // ErrVLATooShort is returned when payload is too short. + ErrVLATooShort = errors.New("VLA payload too short") + // ErrVLAInvalidStreamCount is returned when RTP stream count is invalid. + ErrVLAInvalidStreamCount = errors.New("invalid RTP stream count in VLA") + // ErrVLAInvalidStreamID is returned when RTP stream ID is invalid. + ErrVLAInvalidStreamID = errors.New("invalid RTP stream ID in VLA") + // ErrVLAInvalidSpatialID is returned when spatial ID is invalid. + ErrVLAInvalidSpatialID = errors.New("invalid spatial ID in VLA") + // ErrVLADuplicateSpatialID is returned when spatial ID is invalid. + ErrVLADuplicateSpatialID = errors.New("duplicate spatial ID in VLA") + // ErrVLAInvalidTemporalLayer is returned when temporal layer is invalid. + ErrVLAInvalidTemporalLayer = errors.New("invalid temporal layer in VLA") ) // SpatialLayer is a spatial layer in VLA. @@ -68,6 +74,7 @@ func (v VLA) preprocessForMashaling(ctx *vlaMarshalingContext) error { } ctx.sls[sl.RTPStreamID][sl.SpatialID] = &sl } + return nil } @@ -76,7 +83,7 @@ func (v VLA) encodeTargetBitrates(ctx *vlaMarshalingContext) { for spatialID := 0; spatialID < 4; spatialID++ { if sl := ctx.sls[rtpStreamID][spatialID]; sl != nil { for _, kbps := range sl.TargetBitrates { - leb128 := obu.WriteToLeb128(uint(kbps)) + leb128 := obu.WriteToLeb128(uint(kbps)) // nolint: gosec ctx.encodedTargetBitrates = append(ctx.encodedTargetBitrates, leb128) ctx.requiredLen += len(leb128) } @@ -123,7 +130,7 @@ func (v VLA) analyzeVLAForMarshaling() (*vlaMarshalingContext, error) { } // Marshal encodes VLA into a byte slice. -func (v VLA) Marshal() ([]byte, error) { +func (v VLA) Marshal() ([]byte, error) { // nolint: cyclop ctx, err := v.analyzeVLAForMarshaling() if err != nil { return nil, err @@ -174,8 +181,8 @@ func (v VLA) Marshal() ([]byte, error) { // Resolution & framerate fields if v.HasResolutionAndFramerate { for _, sl := range v.ActiveSpatialLayer { - binary.BigEndian.PutUint16(payload[offset+0:], uint16(sl.Width-1)) - binary.BigEndian.PutUint16(payload[offset+2:], uint16(sl.Height-1)) + binary.BigEndian.PutUint16(payload[offset+0:], uint16(sl.Width-1)) // nolint: gosec + binary.BigEndian.PutUint16(payload[offset+2:], uint16(sl.Height-1)) // nolint: gosec payload[offset+4] = byte(sl.Framerate) offset += 5 } @@ -192,12 +199,14 @@ func commonSLBMValues(slMBs []uint8) uint8 { } if common == 0 { common = slMBs[i] + continue } if slMBs[i] != common { return 0 } } + return common } @@ -247,7 +256,7 @@ func (v *VLA) unmarshalSpatialLayers(ctx *vlaUnmarshalingContext) error { return nil } -func (v *VLA) unmarshalTemporalLayers(ctx *vlaUnmarshalingContext) error { +func (v *VLA) unmarshalTemporalLayers(ctx *vlaUnmarshalingContext) error { // nolint: cyclop if !ctx.checkRemainingLen(1) { return fmt.Errorf("failed to unmarshal VLA (offset=%d): %w", ctx.offset, ErrVLATooShort) } @@ -284,11 +293,14 @@ func (v *VLA) unmarshalTemporalLayers(ctx *vlaUnmarshalingContext) error { if err != nil { return err } - if !ctx.checkRemainingLen(int(n)) { + + in := int(n) // nolint: gosec + + if !ctx.checkRemainingLen(in) { return fmt.Errorf("failed to unmarshal VLA (offset=%d): %w", ctx.offset, ErrVLATooShort) } - v.ActiveSpatialLayer[i].TargetBitrates[j] = int(kbps) - ctx.offset += int(n) + v.ActiveSpatialLayer[i].TargetBitrates[j] = int(kbps) // nolint: gosec + ctx.offset += in } } @@ -356,5 +368,6 @@ func (v VLA) String() string { slOut = append(slOut, out2) } out += fmt.Sprintf(",ActiveSpatialLayers:{%s}", strings.Join(slOut, ",")) + return out } diff --git a/vlaextension_test.go b/vlaextension_test.go index b9b8066..73e9595 100644 --- a/vlaextension_test.go +++ b/vlaextension_test.go @@ -11,8 +11,10 @@ import ( "testing" ) -func TestVLAMarshal(t *testing.T) { +func TestVLAMarshal(t *testing.T) { // nolint: funlen,cyclop requireNoError := func(t *testing.T, err error) { + t.Helper() + if err != nil { t.Fatal(err) } @@ -242,23 +244,31 @@ func TestVLAMarshal(t *testing.T) { }) } -func TestVLAUnmarshal(t *testing.T) { +func TestVLAUnmarshal(t *testing.T) { // nolint: funlen requireEqualInt := func(t *testing.T, expected, actual int) { + t.Helper() + if expected != actual { t.Fatalf("expected %d, actual %d", expected, actual) } } requireNoError := func(t *testing.T, err error) { + t.Helper() + if err != nil { t.Fatal(err) } } requireTrue := func(t *testing.T, val bool) { + t.Helper() + if !val { t.Fatal("expected true") } } requireFalse := func(t *testing.T, val bool) { + t.Helper() + if val { t.Fatal("expected false") } @@ -425,13 +435,17 @@ func TestVLAUnmarshal(t *testing.T) { }) } -func TestVLAMarshalThenUnmarshal(t *testing.T) { +func TestVLAMarshalThenUnmarshal(t *testing.T) { // nolint:funlen, cyclop requireEqualInt := func(t *testing.T, expected, actual int) { + t.Helper() + if expected != actual { t.Fatalf("expected %d, actual %d", expected, actual) } } requireNoError := func(t *testing.T, err error) { + t.Helper() + if err != nil { t.Fatal(err) }