New Upstream Snapshot - golang-github-pion-srtp.v2

Ready changes

Summary

Merged new upstream version: 2.0.12+git20230209.1.b173a46 (was: 2.0.9).

Diff

diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index f977e74..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,25 +0,0 @@
-### JetBrains IDE ###
-#####################
-.idea/
-
-### Emacs Temporary Files ###
-#############################
-*~
-
-### Folders ###
-###############
-bin/
-vendor/
-node_modules/
-
-### Files ###
-#############
-*.ivf
-*.ogg
-tags
-cover.out
-*.sw[poe]
-*.wasm
-examples/sfu-ws/cert.pem
-examples/sfu-ws/key.pem
-wasm_exec.js
diff --git a/.golangci.yml b/.golangci.yml
index d7a88ec..48696f1 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -18,7 +18,6 @@ linters:
     - bidichk          # Checks for dangerous unicode character sequences
     - bodyclose        # checks whether HTTP response body is closed successfully
     - contextcheck     # check the function whether use a non-inherited context
-    - deadcode         # Finds unused code
     - decorder         # check declaration order and count of types, constants, variables and functions
     - depguard         # Go linter that checks if package imports are in a list of acceptable packages
     - dogsled          # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
@@ -60,7 +59,6 @@ linters:
     - predeclared      # find code that shadows one of Go's predeclared identifiers
     - revive           # golint replacement, finds style mistakes
     - staticcheck      # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
-    - structcheck      # Finds unused struct fields
     - 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
@@ -69,7 +67,6 @@ linters:
     - unconvert        # Remove unnecessary type conversions
     - unparam          # Reports unused function parameters
     - unused           # Checks Go code for unused constants, variables, functions and types
-    - varcheck         # Finds unused global variables and constants
     - wastedassign     # wastedassign finds wasted assignment statements
     - whitespace       # Tool for detection of leading and trailing whitespace
   disable:
diff --git a/.goreleaser.yml b/.goreleaser.yml
new file mode 100644
index 0000000..2caa5fb
--- /dev/null
+++ b/.goreleaser.yml
@@ -0,0 +1,2 @@
+builds:
+- skip: true
diff --git a/AUTHORS.txt b/AUTHORS.txt
index 2f9cade..2a17730 100644
--- a/AUTHORS.txt
+++ b/AUTHORS.txt
@@ -2,7 +2,7 @@
 # we would love to have you https://github.com/pion/webrtc/wiki/Contributing
 #
 # This file is auto generated, using git to list all individuals contributors.
-# see `.github/generate-authors.sh` for the scripting
+# see https://github.com/pion/.goassets/blob/master/scripts/generate-authors.sh for the scripting
 adamroach <adam@nostrum.com>
 Adrian Cable <adrian.cable@gmail.com>
 Agniva De Sarker <agnivade@yahoo.co.in>
@@ -25,3 +25,6 @@ Sean DuBois <sean@siobud.com>
 Tobias Fridén <tobias.friden@gmail.com>
 Woodrow Douglass <wdouglass@carnegierobotics.com>
 Yutaka Takeda <yt0916@gmail.com>
+
+# List of contributors not appearing in Git history
+
diff --git a/context.go b/context.go
index bf871b2..438a51c 100644
--- a/context.go
+++ b/context.go
@@ -3,7 +3,7 @@ package srtp
 import (
 	"fmt"
 
-	"github.com/pion/transport/replaydetector"
+	"github.com/pion/transport/v2/replaydetector"
 )
 
 const (
@@ -16,6 +16,7 @@ const (
 	labelSRTCPSalt              = 0x05
 
 	maxSequenceNumber = 65535
+	maxROC            = (1 << 32) - 1
 
 	seqNumMedian = 1 << 15
 	seqNumMax    = 1 << 16
@@ -60,8 +61,7 @@ type Context struct {
 // Passing multiple options which set the same parameter let the last one valid.
 // Following example create SRTP Context with replay protection with window size of 256.
 //
-//   decCtx, err := srtp.CreateContext(key, salt, profile, srtp.SRTPReplayProtection(256))
-//
+//	decCtx, err := srtp.CreateContext(key, salt, profile, srtp.SRTPReplayProtection(256))
 func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts ...ContextOption) (c *Context, err error) {
 	keyLen, err := profile.keyLen()
 	if err != nil {
@@ -112,7 +112,7 @@ func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts
 }
 
 // https://tools.ietf.org/html/rfc3550#appendix-A.1
-func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (uint32, int32) {
+func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (roc uint32, diff int32, overflow bool) {
 	seq := int32(sequenceNumber)
 	localRoc := uint32(s.index >> 16)
 	localSeq := int32(s.index & (seqNumMax - 1))
@@ -147,7 +147,7 @@ func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (uint32, int32)
 		}
 	}
 
-	return guessRoc, difference
+	return guessRoc, difference, (guessRoc == 0 && localRoc == maxROC)
 }
 
 func (s *srtpSSRCState) updateRolloverCount(sequenceNumber uint16, difference int32) {
@@ -201,7 +201,8 @@ func (c *Context) ROC(ssrc uint32) (uint32, bool) {
 // SetROC sets SRTP rollover counter value of specified SSRC.
 func (c *Context) SetROC(ssrc uint32, roc uint32) {
 	s := c.getSRTPSSRCState(ssrc)
-	s.index = uint64(roc<<16) | (s.index & (seqNumMax - 1))
+	s.index = uint64(roc) << 16
+	s.rolloverHasProcessed = false
 }
 
 // Index returns SRTCP index value of specified SSRC.
diff --git a/crypto.go b/crypto.go
index e2eb9b2..0625e91 100644
--- a/crypto.go
+++ b/crypto.go
@@ -2,25 +2,9 @@ package srtp
 
 import (
 	"crypto/cipher"
-)
-
-// xorBytes computes the exclusive-or of src1 and src2 and stores it in dst.
-// It returns the number of bytes written.
-func xorBytes(dst, src1, src2 []byte) int {
-	n := len(src1)
-	if len(src2) < n {
-		n = len(src2)
-	}
-	if len(dst) < n {
-		n = len(dst)
-	}
 
-	for i := 0; i < n; i++ {
-		dst[i] = src1[i] ^ src2[i]
-	}
-
-	return n
-}
+	"github.com/pion/transport/v2/utils/xor"
+)
 
 // incrementCTR increments a big-endian integer of arbitrary size.
 func incrementCTR(ctr []byte) {
@@ -48,7 +32,7 @@ func xorBytesCTR(block cipher.Block, iv []byte, dst, src []byte) error {
 	for i < len(src) {
 		block.Encrypt(stream, ctr)
 		incrementCTR(ctr)
-		n := xorBytes(dst[i:], src[i:], stream)
+		n := xor.XorBytes(dst[i:], src[i:], stream)
 		if n == 0 {
 			break
 		}
diff --git a/crypto_test.go b/crypto_test.go
index 4a5bf8f..fe98e0f 100644
--- a/crypto_test.go
+++ b/crypto_test.go
@@ -62,22 +62,3 @@ func TestXorBytesCTRInvalidIvLength(t *testing.T) {
 	test(make([]byte, block.BlockSize()-1))
 	test(make([]byte, block.BlockSize()+1))
 }
-
-func TestXorBytesBufferSize(t *testing.T) {
-	a := []byte{3}
-	b := []byte{5, 6}
-	dst := make([]byte, 3)
-
-	xorBytes(dst, a, b)
-	require.Equal(t, dst, []byte{6, 0, 0})
-
-	xorBytes(dst, b, a)
-	require.Equal(t, dst, []byte{6, 0, 0})
-
-	a = []byte{1, 1, 1, 1}
-	b = []byte{2, 2, 2, 2}
-	dst = make([]byte, 3)
-
-	xorBytes(dst, a, b)
-	require.Equal(t, dst, []byte{3, 3, 3})
-}
diff --git a/debian/changelog b/debian/changelog
index fd25483..d5590eb 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+golang-github-pion-srtp.v2 (2.0.12+git20230209.1.b173a46-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 09 Feb 2023 18:55:29 -0000
+
 golang-github-pion-srtp.v2 (2.0.9-2) unstable; urgency=medium
 
   * Source-only upload.
diff --git a/errors.go b/errors.go
index 55a67bc..db5b7db 100644
--- a/errors.go
+++ b/errors.go
@@ -19,6 +19,7 @@ var (
 	errPayloadDiffers                = errors.New("payload differs")
 	errStartedChannelUsedIncorrectly = errors.New("started channel used incorrectly, should only be closed")
 	errBadIVLength                   = errors.New("bad iv length in xorBytesCTR")
+	errExceededMaxPackets            = errors.New("exceeded the maximum number of packets")
 
 	errStreamNotInited     = errors.New("stream has not been inited, unable to close")
 	errStreamAlreadyClosed = errors.New("stream is already closed")
diff --git a/go.mod b/go.mod
index 9f0e9a6..223d2d3 100644
--- a/go.mod
+++ b/go.mod
@@ -4,8 +4,8 @@ go 1.14
 
 require (
 	github.com/pion/logging v0.2.2
-	github.com/pion/rtcp v1.2.9
+	github.com/pion/rtcp v1.2.10
 	github.com/pion/rtp v1.7.13
-	github.com/pion/transport v0.13.0
-	github.com/stretchr/testify v1.7.1
+	github.com/pion/transport/v2 v2.0.1
+	github.com/stretchr/testify v1.8.1
 )
diff --git a/go.sum b/go.sum
index 4b2d50e..9ab67ed 100644
--- a/go.sum
+++ b/go.sum
@@ -1,29 +1,56 @@
-github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
 github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
 github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
 github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/rtcp v1.2.9 h1:1ujStwg++IOLIEoOiIQ2s+qBuJ1VN81KW+9pMPsif+U=
-github.com/pion/rtcp v1.2.9/go.mod h1:qVPhiCzAm4D/rxb6XzKeyZiQK69yJpbUDJSF7TgrqNo=
+github.com/pion/rtcp v1.2.10 h1:nkr3uj+8Sp97zyItdN60tE/S6vk4al5CPRR6Gejsdjc=
+github.com/pion/rtcp v1.2.10/go.mod h1:ztfEwXZNLGyF1oQDttz/ZKIBaeeg/oWbRYqzBM9TL1I=
 github.com/pion/rtp v1.7.13 h1:qcHwlmtiI50t1XivvoawdCGTP4Uiypzfrsap+bijcoA=
 github.com/pion/rtp v1.7.13/go.mod h1:bDb5n+BFZxXx0Ea7E5qe+klMuqiBrP+w8XSjiWtCUko=
-github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
-github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
+github.com/pion/transport/v2 v2.0.1 h1:cbSk3gzoSBEIKVGNYeghXQSp47s1H9ttoP5JyLCgxLE=
+github.com/pion/transport/v2 v2.0.1/go.mod h1:93OYg91+mrGxKW+Jrgzmqr80kgXqD7J0yybOrdr7w0Y=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
+github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
+github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c h1:WtYZ93XtWSO5KlOMgPZu7hXY9WhMZpprvlm5VwvAl8c=
-golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
+golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
+golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
+golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
+golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/option.go b/option.go
index 86ecd8e..84df19c 100644
--- a/option.go
+++ b/option.go
@@ -1,7 +1,7 @@
 package srtp
 
 import (
-	"github.com/pion/transport/replaydetector"
+	"github.com/pion/transport/v2/replaydetector"
 )
 
 // ContextOption represents option of Context using the functional options pattern.
@@ -11,7 +11,7 @@ type ContextOption func(*Context) error
 func SRTPReplayProtection(windowSize uint) ContextOption { // nolint:revive
 	return func(c *Context) error {
 		c.newSRTPReplayDetector = func() replaydetector.ReplayDetector {
-			return replaydetector.WithWrap(windowSize, maxSequenceNumber)
+			return replaydetector.New(windowSize, maxROC<<16|maxSequenceNumber)
 		}
 		return nil
 	}
@@ -21,7 +21,7 @@ func SRTPReplayProtection(windowSize uint) ContextOption { // nolint:revive
 func SRTCPReplayProtection(windowSize uint) ContextOption {
 	return func(c *Context) error {
 		c.newSRTCPReplayDetector = func() replaydetector.ReplayDetector {
-			return replaydetector.WithWrap(windowSize, maxSRTCPIndex)
+			return replaydetector.New(windowSize, maxSRTCPIndex)
 		}
 		return nil
 	}
diff --git a/renovate.json b/renovate.json
index f161405..f1bb98c 100644
--- a/renovate.json
+++ b/renovate.json
@@ -1,27 +1,6 @@
 {
+  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
   "extends": [
-    "config:base",
-    ":disableDependencyDashboard"
-  ],
-  "postUpdateOptions": [
-    "gomodTidy"
-  ],
-  "commitBody": "Generated by renovateBot",
-  "packageRules": [
-    {
-      "matchUpdateTypes": ["minor", "patch", "pin", "digest"],
-      "automerge": true
-    },
-    {
-      "packagePatterns": ["^golang.org/x/"],
-      "schedule": ["on the first day of the month"]
-    }
-  ],
-  "ignorePaths": [
-    ".github/workflows/generate-authors.yml",
-    ".github/workflows/lint.yaml",
-    ".github/workflows/renovate-go-mod-fix.yaml",
-    ".github/workflows/test.yaml",
-    ".github/workflows/tidy-check.yaml"
+    "github>pion/renovate-config"
   ]
 }
diff --git a/session.go b/session.go
index 8148aff..f72dcda 100644
--- a/session.go
+++ b/session.go
@@ -7,7 +7,7 @@ import (
 	"sync"
 
 	"github.com/pion/logging"
-	"github.com/pion/transport/packetio"
+	"github.com/pion/transport/v2/packetio"
 )
 
 type streamSession interface {
diff --git a/session_srtcp_test.go b/session_srtcp_test.go
index b2043d7..4314011 100644
--- a/session_srtcp_test.go
+++ b/session_srtcp_test.go
@@ -12,7 +12,7 @@ import (
 	"time"
 
 	"github.com/pion/rtcp"
-	"github.com/pion/transport/test"
+	"github.com/pion/transport/v2/test"
 )
 
 const rtcpHeaderSize = 4
diff --git a/session_srtp_test.go b/session_srtp_test.go
index a3798ba..1143c50 100644
--- a/session_srtp_test.go
+++ b/session_srtp_test.go
@@ -11,7 +11,7 @@ import (
 	"time"
 
 	"github.com/pion/rtp"
-	"github.com/pion/transport/test"
+	"github.com/pion/transport/v2/test"
 )
 
 func TestSessionSRTPBadInit(t *testing.T) {
diff --git a/srtcp.go b/srtcp.go
index d3e387b..2812851 100644
--- a/srtcp.go
+++ b/srtcp.go
@@ -63,11 +63,16 @@ func (c *Context) encryptRTCP(dst, decrypted []byte) ([]byte, error) {
 	ssrc := binary.BigEndian.Uint32(decrypted[4:])
 	s := c.getSRTCPSSRCState(ssrc)
 
+	if s.srtcpIndex >= maxSRTCPIndex {
+		// ... when 2^48 SRTP packets or 2^31 SRTCP packets have been secured with the same key
+		// (whichever occurs before), the key management MUST be called to provide new master key(s)
+		// (previously stored and used keys MUST NOT be used again), or the session MUST be terminated.
+		// https://www.rfc-editor.org/rfc/rfc3711#section-9.2
+		return nil, errExceededMaxPackets
+	}
+
 	// We roll over early because MSB is used for marking as encrypted
 	s.srtcpIndex++
-	if s.srtcpIndex > maxSRTCPIndex {
-		s.srtcpIndex = 0
-	}
 
 	return c.cipher.encryptRTCP(dst, decrypted, s.srtcpIndex, ssrc)
 }
diff --git a/srtcp_test.go b/srtcp_test.go
index f2e870d..96133ab 100644
--- a/srtcp_test.go
+++ b/srtcp_test.go
@@ -25,7 +25,7 @@ type rtcpTestCase struct {
 	packets    []rtcpTestPacket
 }
 
-func rtcpTestCasesSingle() map[string]rtcpTestCase {
+func rtcpTestCases() map[string]rtcpTestCase {
 	return map[string]rtcpTestCase{
 		"AEAD_AES_128_GCM": {
 			algo:       ProtectionProfileAeadAes128Gcm,
@@ -112,72 +112,6 @@ func rtcpTestCasesSingle() map[string]rtcpTestCase {
 	}
 }
 
-func rtcpTestCases() map[string]rtcpTestCase {
-	single := rtcpTestCasesSingle()
-	return map[string]rtcpTestCase{
-		"AEAD_AES_128_GCM": single["AEAD_AES_128_GCM"],
-		"AES_128_CM_HMAC_SHA1_80": {
-			algo:       ProtectionProfileAes128CmHmacSha1_80,
-			masterKey:  single["AES_128_CM_HMAC_SHA1_80"].masterKey,
-			masterSalt: single["AES_128_CM_HMAC_SHA1_80"].masterSalt,
-			packets: []rtcpTestPacket{
-				single["AES_128_CM_HMAC_SHA1_80"].packets[0],
-				single["AES_128_CM_HMAC_SHA1_80"].packets[1],
-				{
-					ssrc:    0x11111111,
-					index:   0x7ffffffe, // Upper boundary of index
-					pktType: rtcp.TypeSenderReport,
-					encrypted: []byte{
-						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
-						0x17, 0x8c, 0x15, 0xf1, 0x4b, 0x11, 0xda, 0xf5,
-						0x74, 0x53, 0x86, 0x2b, 0xc9, 0x07, 0x29, 0x40,
-						0xbf, 0x22, 0xf6, 0x46, 0x11, 0xa4, 0xc1, 0x3a,
-						0xff, 0x5a, 0xbd, 0xd0, 0xf8, 0x8b, 0x38, 0xe4,
-						0x95, 0x38, 0x5d, 0xcf, 0x1b, 0xf5, 0x27, 0x77,
-						0xfb, 0xdb, 0x3f, 0x10, 0x68, 0x99, 0xd8, 0xad,
-						0xff, 0xff, 0xff, 0xff, 0x5a, 0x99, 0xce, 0xed,
-						0x9f, 0x2e, 0x4d, 0x9d, 0xfa, 0x97,
-					},
-					decrypted: []byte{
-						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
-						0x04, 0x99, 0x47, 0x53, 0xc4, 0x1e, 0xb9, 0xde,
-						0x52, 0xa3, 0x1d, 0x77, 0x2f, 0xff, 0xcc, 0x75,
-						0xbb, 0x6a, 0x29, 0xb8, 0x01, 0xb7, 0x2e, 0x4b,
-						0x4e, 0xcb, 0xa4, 0x81, 0x2d, 0x46, 0x04, 0x5e,
-						0x86, 0x90, 0x17, 0x4f, 0x4d, 0x78, 0x2f, 0x58,
-						0xb8, 0x67, 0x91, 0x89, 0xe3, 0x61, 0x01, 0x7d,
-					},
-				},
-				{
-					ssrc:    0x11111111,
-					index:   0x7fffffff, // Will be wrapped to 0
-					pktType: rtcp.TypeSenderReport,
-					encrypted: []byte{
-						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
-						0x17, 0x8c, 0x15, 0xf1, 0x4b, 0x11, 0xda, 0xf5,
-						0x74, 0x53, 0x86, 0x2b, 0xc9, 0x07, 0x29, 0x40,
-						0xbf, 0x22, 0xf6, 0x46, 0x11, 0xa4, 0xc1, 0x3a,
-						0xff, 0x5a, 0xbd, 0xd0, 0xf8, 0x8b, 0x38, 0xe4,
-						0x95, 0x38, 0x5d, 0xcf, 0x1b, 0xf5, 0x27, 0x77,
-						0xfb, 0xdb, 0x3f, 0x10, 0x68, 0x99, 0xd8, 0xad,
-						0x80, 0x00, 0x00, 0x00, 0x7d, 0x51, 0xf8, 0x0e,
-						0x56, 0x40, 0x72, 0x7b, 0x9e, 0x02,
-					},
-					decrypted: []byte{
-						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
-						0xda, 0xb5, 0xe0, 0x56, 0x9a, 0x4a, 0x74, 0xed,
-						0x8a, 0x54, 0x0c, 0xcf, 0xd5, 0x09, 0xb1, 0x40,
-						0x01, 0x42, 0xc3, 0x9a, 0x76, 0x00, 0xa9, 0xd4,
-						0xf7, 0x29, 0x9e, 0x51, 0xfb, 0x3c, 0xc1, 0x74,
-						0x72, 0xf9, 0x52, 0xb1, 0x92, 0x31, 0xca, 0x22,
-						0xab, 0x3e, 0xc5, 0x5f, 0x83, 0x34, 0xf0, 0x28,
-					},
-				},
-			},
-		},
-	}
-}
-
 func TestRTCPLifecycle(t *testing.T) {
 	options := map[string][]ContextOption{
 		"Default":              {},
@@ -371,7 +305,7 @@ func TestRTCPInvalidAuthTag(t *testing.T) {
 }
 
 func TestRTCPReplayDetectorSeparation(t *testing.T) {
-	for caseName, testCase := range rtcpTestCasesSingle() {
+	for caseName, testCase := range rtcpTestCases() {
 		testCase := testCase
 		t.Run(caseName, func(t *testing.T) {
 			assert := assert.New(t)
@@ -409,7 +343,7 @@ func getRTCPIndex(encrypted []byte, authTagLen int) uint32 {
 }
 
 func TestEncryptRTCPSeparation(t *testing.T) {
-	for caseName, testCase := range rtcpTestCasesSingle() {
+	for caseName, testCase := range rtcpTestCases() {
 		testCase := testCase
 		t.Run(caseName, func(t *testing.T) {
 			assert := assert.New(t)
@@ -462,7 +396,7 @@ func TestEncryptRTCPSeparation(t *testing.T) {
 }
 
 func TestRTCPDecryptShortenedPacket(t *testing.T) {
-	for caseName, testCase := range rtcpTestCasesSingle() {
+	for caseName, testCase := range rtcpTestCases() {
 		testCase := testCase
 		t.Run(caseName, func(t *testing.T) {
 			pkt := testCase.packets[0]
@@ -479,3 +413,157 @@ func TestRTCPDecryptShortenedPacket(t *testing.T) {
 		})
 	}
 }
+
+func TestRTCPMaxPackets(t *testing.T) {
+	const ssrc = 0x11111111
+	testCases := map[string]rtcpTestCase{
+		"AEAD_AES_128_GCM": {
+			algo:       ProtectionProfileAeadAes128Gcm,
+			masterKey:  []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+			masterSalt: []byte{0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab},
+			packets: []rtcpTestPacket{
+				{
+					pktType: rtcp.TypeSenderReport,
+					encrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x02, 0xb6, 0xc1, 0x47, 0x92, 0xbe, 0xf0, 0xae,
+						0xd9, 0x40, 0xa5, 0x1c, 0xbe, 0xec, 0xaf, 0xfc,
+						0x7d, 0x86, 0x3b, 0xbb, 0x93, 0x0c, 0xb0, 0xd4,
+						0xea, 0x4a, 0x3c, 0x5b, 0xd1, 0xd5, 0x47, 0xb1,
+						0x1a, 0x61, 0xae, 0xa6, 0x1a, 0x0c, 0xb9, 0x14,
+						0xa5, 0x16, 0x08, 0xe4, 0xfb, 0x0d, 0x15, 0xba,
+						0x7f, 0x70, 0x2b, 0xb8, 0x99, 0x97, 0x91, 0xfd,
+						0x53, 0x03, 0xcd, 0x57, 0xbb, 0x8f, 0x93, 0xbe,
+						0xff, 0xff, 0xff, 0xff,
+					},
+					decrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x04, 0x99, 0x47, 0x53, 0xc4, 0x1e, 0xb9, 0xde,
+						0x52, 0xa3, 0x1d, 0x77, 0x2f, 0xff, 0xcc, 0x75,
+						0xbb, 0x6a, 0x29, 0xb8, 0x01, 0xb7, 0x2e, 0x4b,
+						0x4e, 0xcb, 0xa4, 0x81, 0x2d, 0x46, 0x04, 0x5e,
+						0x86, 0x90, 0x17, 0x4f, 0x4d, 0x78, 0x2f, 0x58,
+						0xb8, 0x67, 0x91, 0x89, 0xe3, 0x61, 0x01, 0x7d,
+					},
+				},
+				{
+					pktType: rtcp.TypeSenderReport,
+					encrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x77, 0x47, 0x0c, 0x21, 0xc2, 0xcd, 0x33, 0xa7,
+						0x5a, 0x81, 0xb5, 0xb5, 0x8f, 0xe2, 0x34, 0x28,
+						0x11, 0xa8, 0xa3, 0x34, 0xf8, 0x9d, 0xfc, 0xd8,
+						0xcb, 0x87, 0xe2, 0x51, 0x8e, 0xae, 0xdb, 0xfd,
+						0x9d, 0xf1, 0xfa, 0x18, 0xe2, 0xdc, 0x0a, 0xd4,
+						0xe3, 0x06, 0x18, 0xff, 0xf7, 0x27, 0x92, 0x1f,
+						0x28, 0xcd, 0x3c, 0xf8, 0xa4, 0x0a, 0x2b, 0xbb,
+						0x5b, 0x1f, 0x4d, 0x1f, 0xef, 0x0e, 0xc4, 0x91,
+						0x80, 0x00, 0x00, 0x01,
+					},
+					decrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0xda, 0xb5, 0xe0, 0x56, 0x9a, 0x4a, 0x74, 0xed,
+						0x8a, 0x54, 0x0c, 0xcf, 0xd5, 0x09, 0xb1, 0x40,
+						0x01, 0x42, 0xc3, 0x9a, 0x76, 0x00, 0xa9, 0xd4,
+						0xf7, 0x29, 0x9e, 0x51, 0xfb, 0x3c, 0xc1, 0x74,
+						0x72, 0xf9, 0x52, 0xb1, 0x92, 0x31, 0xca, 0x22,
+						0xab, 0x3e, 0xc5, 0x5f, 0x83, 0x34, 0xf0, 0x28,
+					},
+				},
+			},
+		},
+		"AES_128_CM_HMAC_SHA1_80": {
+			algo:       ProtectionProfileAes128CmHmacSha1_80,
+			masterKey:  []byte{0xfd, 0xa6, 0x25, 0x95, 0xd7, 0xf6, 0x92, 0x6f, 0x7d, 0x9c, 0x02, 0x4c, 0xc9, 0x20, 0x9f, 0x34},
+			masterSalt: []byte{0xa9, 0x65, 0x19, 0x85, 0x54, 0x0b, 0x47, 0xbe, 0x2f, 0x27, 0xa8, 0xb8, 0x81, 0x23},
+			packets: []rtcpTestPacket{
+				{
+					encrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x17, 0x8c, 0x15, 0xf1, 0x4b, 0x11, 0xda, 0xf5,
+						0x74, 0x53, 0x86, 0x2b, 0xc9, 0x07, 0x29, 0x40,
+						0xbf, 0x22, 0xf6, 0x46, 0x11, 0xa4, 0xc1, 0x3a,
+						0xff, 0x5a, 0xbd, 0xd0, 0xf8, 0x8b, 0x38, 0xe4,
+						0x95, 0x38, 0x5d, 0xcf, 0x1b, 0xf5, 0x27, 0x77,
+						0xfb, 0xdb, 0x3f, 0x10, 0x68, 0x99, 0xd8, 0xad,
+						0xff, 0xff, 0xff, 0xff, 0x5a, 0x99, 0xce, 0xed,
+						0x9f, 0x2e, 0x4d, 0x9d, 0xfa, 0x97,
+					},
+					decrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x04, 0x99, 0x47, 0x53, 0xc4, 0x1e, 0xb9, 0xde,
+						0x52, 0xa3, 0x1d, 0x77, 0x2f, 0xff, 0xcc, 0x75,
+						0xbb, 0x6a, 0x29, 0xb8, 0x01, 0xb7, 0x2e, 0x4b,
+						0x4e, 0xcb, 0xa4, 0x81, 0x2d, 0x46, 0x04, 0x5e,
+						0x86, 0x90, 0x17, 0x4f, 0x4d, 0x78, 0x2f, 0x58,
+						0xb8, 0x67, 0x91, 0x89, 0xe3, 0x61, 0x01, 0x7d,
+					},
+				},
+				{
+					encrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0x12, 0x71, 0x75, 0x7a, 0xb0, 0xfd, 0x80, 0xcb,
+						0x26, 0xbb, 0x54, 0x5a, 0x1c, 0x0e, 0x98, 0x09,
+						0xbe, 0x60, 0x23, 0xd8, 0xe6, 0x6e, 0x68, 0xe8,
+						0x6e, 0x9c, 0xb2, 0x7e, 0x02, 0xa7, 0xab, 0xfe,
+						0xb3, 0xf4, 0x4c, 0x13, 0xc3, 0xac, 0x97, 0x2c,
+						0x35, 0x91, 0xbb, 0x37, 0x9c, 0x86, 0x28, 0x85,
+						0x80, 0x00, 0x00, 0x01, 0x89, 0x76, 0x07, 0xca,
+						0xd9, 0xc4, 0xcb, 0xca, 0x66, 0xab,
+					},
+					decrypted: []byte{
+						0x80, 0xc8, 0x00, 0x06, 0x11, 0x11, 0x11, 0x11,
+						0xda, 0xb5, 0xe0, 0x56, 0x9a, 0x4a, 0x74, 0xed,
+						0x8a, 0x54, 0x0c, 0xcf, 0xd5, 0x09, 0xb1, 0x40,
+						0x01, 0x42, 0xc3, 0x9a, 0x76, 0x00, 0xa9, 0xd4,
+						0xf7, 0x29, 0x9e, 0x51, 0xfb, 0x3c, 0xc1, 0x74,
+						0x72, 0xf9, 0x52, 0xb1, 0x92, 0x31, 0xca, 0x22,
+						0xab, 0x3e, 0xc5, 0x5f, 0x83, 0x34, 0xf0, 0x28,
+					},
+				},
+			},
+		},
+	}
+
+	for caseName, testCase := range testCases {
+		testCase := testCase
+		t.Run(caseName, func(t *testing.T) {
+			assert := assert.New(t)
+			encryptContext, err := CreateContext(testCase.masterKey, testCase.masterSalt, testCase.algo)
+			if err != nil {
+				t.Errorf("CreateContext failed: %v", err)
+			}
+
+			decryptContext, err := CreateContext(testCase.masterKey, testCase.masterSalt, testCase.algo, SRTCPReplayProtection(10))
+			if err != nil {
+				t.Errorf("CreateContext failed: %v", err)
+			}
+
+			// Upper boundary of index
+			encryptContext.SetIndex(ssrc, 0x7ffffffe)
+
+			decryptResult, err := decryptContext.DecryptRTCP(nil, testCase.packets[0].encrypted, nil)
+			if err != nil {
+				t.Error(err)
+			}
+			assert.Equal(testCase.packets[0].decrypted, decryptResult, "RTCP failed to decrypt")
+
+			encryptResult, err := encryptContext.EncryptRTCP(nil, testCase.packets[0].decrypted, nil)
+			if err != nil {
+				t.Error(err)
+			}
+			assert.Equal(testCase.packets[0].encrypted, encryptResult, "RTCP failed to encrypt")
+
+			// Next packet will exceeds the maximum packet count
+			_, err = decryptContext.DecryptRTCP(nil, testCase.packets[1].encrypted, nil)
+			if !errors.Is(err, errDuplicated) {
+				t.Errorf("Expected error: '%v', got: '%v'", errDuplicated, err)
+			}
+
+			_, err = encryptContext.EncryptRTCP(nil, testCase.packets[1].decrypted, nil)
+			if !errors.Is(err, errExceededMaxPackets) {
+				t.Errorf("Expected error: '%v', got: '%v'", errExceededMaxPackets, err)
+			}
+		})
+	}
+}
diff --git a/srtp.go b/srtp.go
index 0feaf0f..c8ad8a5 100644
--- a/srtp.go
+++ b/srtp.go
@@ -8,7 +8,10 @@ import (
 func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerLen int) ([]byte, error) {
 	s := c.getSRTPSSRCState(header.SSRC)
 
-	markAsValid, ok := s.replayDetector.Check(uint64(header.SequenceNumber))
+	roc, diff, _ := s.nextRolloverCount(header.SequenceNumber)
+	markAsValid, ok := s.replayDetector.Check(
+		(uint64(roc) << 16) | uint64(header.SequenceNumber),
+	)
 	if !ok {
 		return nil, &duplicatedError{
 			Proto: "srtp", SSRC: header.SSRC, Index: uint32(header.SequenceNumber),
@@ -20,7 +23,6 @@ func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerL
 		return nil, err
 	}
 	dst = growBufferSize(dst, len(ciphertext)-authTagLen)
-	roc, diff := s.nextRolloverCount(header.SequenceNumber)
 
 	dst, err = c.cipher.decryptRTP(dst, ciphertext, header, headerLen, roc)
 	if err != nil {
@@ -67,7 +69,14 @@ func (c *Context) EncryptRTP(dst []byte, plaintext []byte, header *rtp.Header) (
 // Similar to above but faster because it can avoid unmarshaling the header and marshaling the payload.
 func (c *Context) encryptRTP(dst []byte, header *rtp.Header, payload []byte) (ciphertext []byte, err error) {
 	s := c.getSRTPSSRCState(header.SSRC)
-	roc, diff := s.nextRolloverCount(header.SequenceNumber)
+	roc, diff, ovf := s.nextRolloverCount(header.SequenceNumber)
+	if ovf {
+		// ... when 2^48 SRTP packets or 2^31 SRTCP packets have been secured with the same key
+		// (whichever occurs before), the key management MUST be called to provide new master key(s)
+		// (previously stored and used keys MUST NOT be used again), or the session MUST be terminated.
+		// https://www.rfc-editor.org/rfc/rfc3711#section-9.2
+		return nil, errExceededMaxPackets
+	}
 	s.updateRolloverCount(header.SequenceNumber, diff)
 
 	return c.cipher.encryptRTP(dst, header, payload, roc)
diff --git a/srtp_test.go b/srtp_test.go
index 8333b48..e239614 100644
--- a/srtp_test.go
+++ b/srtp_test.go
@@ -76,68 +76,104 @@ func TestRolloverCount(t *testing.T) {
 	s := &srtpSSRCState{ssrc: defaultSsrc}
 
 	// Set initial seqnum
-	roc, diff := s.nextRolloverCount(65530)
+	roc, diff, ovf := s.nextRolloverCount(65530)
 	if roc != 0 {
 		t.Errorf("Initial rolloverCounter must be 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(65530, diff)
 
 	// Invalid packets never update ROC
-	_, _ = s.nextRolloverCount(0)
-	_, _ = s.nextRolloverCount(0x4000)
-	_, _ = s.nextRolloverCount(0x8000)
-	_, _ = s.nextRolloverCount(0xFFFF)
-	_, _ = s.nextRolloverCount(0)
+	s.nextRolloverCount(0)
+	s.nextRolloverCount(0x4000)
+	s.nextRolloverCount(0x8000)
+	s.nextRolloverCount(0xFFFF)
+	s.nextRolloverCount(0)
 
 	// We rolled over to 0
-	roc, diff = s.nextRolloverCount(0)
+	roc, diff, ovf = s.nextRolloverCount(0)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was not updated after it crossed 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(0, diff)
 
-	roc, diff = s.nextRolloverCount(65530)
+	roc, diff, ovf = s.nextRolloverCount(65530)
 	if roc != 0 {
 		t.Errorf("rolloverCounter was not updated when it rolled back, failed to handle out of order")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(65530, diff)
 
-	roc, diff = s.nextRolloverCount(5)
+	roc, diff, ovf = s.nextRolloverCount(5)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was not updated when it rolled over initial, to handle out of order")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(5, diff)
 
-	_, diff = s.nextRolloverCount(6)
+	_, diff, _ = s.nextRolloverCount(6)
 	s.updateRolloverCount(6, diff)
-	_, diff = s.nextRolloverCount(7)
+	_, diff, _ = s.nextRolloverCount(7)
 	s.updateRolloverCount(7, diff)
-	roc, diff = s.nextRolloverCount(8)
+	roc, diff, _ = s.nextRolloverCount(8)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
 	s.updateRolloverCount(8, diff)
 
 	// valid packets never update ROC
-	roc, diff = s.nextRolloverCount(0x4000)
+	roc, diff, ovf = s.nextRolloverCount(0x4000)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(0x4000, diff)
-	roc, diff = s.nextRolloverCount(0x8000)
+	roc, diff, ovf = s.nextRolloverCount(0x8000)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(0x8000, diff)
-	roc, diff = s.nextRolloverCount(0xFFFF)
+	roc, diff, ovf = s.nextRolloverCount(0xFFFF)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(0xFFFF, diff)
-	roc, _ = s.nextRolloverCount(0)
+	roc, _, ovf = s.nextRolloverCount(0)
 	if roc != 2 {
 		t.Errorf("rolloverCounter must be incremented after wrapping, got %d", roc)
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
+}
+
+func TestRolloverCountOverflow(t *testing.T) {
+	s := &srtpSSRCState{
+		ssrc:  defaultSsrc,
+		index: maxROC << 16,
+	}
+	s.updateRolloverCount(0xFFFF, 0)
+	_, _, ovf := s.nextRolloverCount(0)
+	if !ovf {
+		t.Error("Should overflow")
+	}
 }
 
 func buildTestContext(profile ProtectionProfile, opts ...ContextOption) (*Context, error) {
@@ -541,57 +577,87 @@ func BenchmarkDecryptRTP(b *testing.B) {
 func TestRolloverCount2(t *testing.T) {
 	s := &srtpSSRCState{ssrc: defaultSsrc}
 
-	roc, diff := s.nextRolloverCount(30123)
+	roc, diff, ovf := s.nextRolloverCount(30123)
 	if roc != 0 {
 		t.Errorf("Initial rolloverCounter must be 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(30123, diff)
 
-	roc, diff = s.nextRolloverCount(62892) // 30123 + (1 << 15) + 1
+	roc, diff, ovf = s.nextRolloverCount(62892) // 30123 + (1 << 15) + 1
 	if roc != 0 {
 		t.Errorf("Initial rolloverCounter must be 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(62892, diff)
-	roc, diff = s.nextRolloverCount(204)
+	roc, diff, ovf = s.nextRolloverCount(204)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was not updated after it crossed 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(62892, diff)
-	roc, diff = s.nextRolloverCount(64535)
+	roc, diff, ovf = s.nextRolloverCount(64535)
 	if roc != 0 {
 		t.Errorf("rolloverCounter was not updated when it rolled back, failed to handle out of order")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(64535, diff)
-	roc, diff = s.nextRolloverCount(205)
+	roc, diff, ovf = s.nextRolloverCount(205)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(205, diff)
-	roc, diff = s.nextRolloverCount(1)
+	roc, diff, ovf = s.nextRolloverCount(1)
 	if roc != 1 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(1, diff)
 
-	roc, diff = s.nextRolloverCount(64532)
+	roc, diff, ovf = s.nextRolloverCount(64532)
 	if roc != 0 {
 		t.Errorf("rolloverCounter was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(64532, diff)
-	roc, diff = s.nextRolloverCount(65534)
+	roc, diff, ovf = s.nextRolloverCount(65534)
 	if roc != 0 {
 		t.Errorf("index was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(65534, diff)
-	roc, diff = s.nextRolloverCount(64532)
+	roc, diff, ovf = s.nextRolloverCount(64532)
 	if roc != 0 {
 		t.Errorf("index was improperly updated for non-significant packets")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(65532, diff)
-	roc, diff = s.nextRolloverCount(205)
+	roc, diff, ovf = s.nextRolloverCount(205)
 	if roc != 1 {
 		t.Errorf("index was not updated after it crossed 0")
 	}
+	if ovf {
+		t.Error("Should not overflow")
+	}
 	s.updateRolloverCount(65532, diff)
 }
 
@@ -660,3 +726,126 @@ func TestRTPDecryptShotenedPacket(t *testing.T) {
 		})
 	}
 }
+
+func TestRTPMaxPackets(t *testing.T) {
+	profiles := map[string]ProtectionProfile{
+		"CTR": profileCTR,
+		"GCM": profileGCM,
+	}
+	for name, profile := range profiles {
+		profile := profile
+		t.Run(name, func(t *testing.T) {
+			context, err := buildTestContext(profile)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			context.SetROC(1, (1<<32)-1)
+
+			pkt0 := &rtp.Packet{
+				Header: rtp.Header{
+					SSRC:           1,
+					SequenceNumber: 0xffff,
+				},
+				Payload: []byte{0, 1},
+			}
+			raw0, err0 := pkt0.Marshal()
+			if err0 != nil {
+				t.Fatal(err0)
+			}
+			if _, errEnc := context.EncryptRTP(nil, raw0, nil); errEnc != nil {
+				t.Fatal(errEnc)
+			}
+
+			pkt1 := &rtp.Packet{
+				Header: rtp.Header{
+					SSRC:           1,
+					SequenceNumber: 0x0,
+				},
+				Payload: []byte{0, 1},
+			}
+			raw1, err1 := pkt1.Marshal()
+			if err1 != nil {
+				t.Fatal(err1)
+			}
+			if _, errEnc := context.EncryptRTP(nil, raw1, nil); !errors.Is(errEnc, errExceededMaxPackets) {
+				t.Fatalf("Expected error '%v', got '%v'", errExceededMaxPackets, errEnc)
+			}
+		})
+	}
+}
+
+func TestRTPBurstLossWithSetROC(t *testing.T) {
+	profiles := map[string]ProtectionProfile{
+		"CTR": profileCTR,
+		"GCM": profileGCM,
+	}
+	for name, profile := range profiles {
+		profile := profile
+		t.Run(name, func(t *testing.T) {
+			assert := assert.New(t)
+
+			encryptContext, err := buildTestContext(profile)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			type packetWithROC struct {
+				pkt rtp.Packet
+				enc []byte
+				raw []byte
+
+				roc uint32
+			}
+
+			var pkts []*packetWithROC
+			encryptContext.SetROC(1, 3)
+			for i := 0x8C00; i < 0x20400; i += 0x100 {
+				p := &packetWithROC{
+					pkt: rtp.Packet{
+						Payload: []byte{
+							byte(i >> 16),
+							byte(i >> 8),
+							byte(i),
+						},
+						Header: rtp.Header{
+							Marker:         true,
+							SSRC:           1,
+							SequenceNumber: uint16(i),
+						},
+					},
+				}
+				b, errMarshal := p.pkt.Marshal()
+				if errMarshal != nil {
+					t.Fatal(errMarshal)
+				}
+				p.raw = b
+				enc, errEnc := encryptContext.EncryptRTP(nil, b, nil)
+				if errEnc != nil {
+					t.Fatal(errEnc)
+				}
+				p.roc, _ = encryptContext.ROC(1)
+				if 0x9000 < i && i < 0x20100 {
+					continue
+				}
+				p.enc = enc
+				pkts = append(pkts, p)
+			}
+
+			decryptContext, err := buildTestContext(profile)
+			if err != nil {
+				t.Fatal(err)
+			}
+
+			for _, p := range pkts {
+				decryptContext.SetROC(1, p.roc)
+				pkt, err := decryptContext.DecryptRTP(nil, p.enc, nil)
+				if err != nil {
+					t.Errorf("roc=%d, seq=%d: %v", p.roc, p.pkt.SequenceNumber, err)
+					continue
+				}
+				assert.Equal(p.raw, pkt)
+			}
+		})
+	}
+}
diff --git a/stream_srtcp.go b/stream_srtcp.go
index e335937..3e0b9ac 100644
--- a/stream_srtcp.go
+++ b/stream_srtcp.go
@@ -7,7 +7,7 @@ import (
 	"time"
 
 	"github.com/pion/rtcp"
-	"github.com/pion/transport/packetio"
+	"github.com/pion/transport/v2/packetio"
 )
 
 // Limit the buffer size to 100KB
diff --git a/stream_srtp.go b/stream_srtp.go
index 8b57c7c..284f88e 100644
--- a/stream_srtp.go
+++ b/stream_srtp.go
@@ -7,7 +7,7 @@ import (
 	"time"
 
 	"github.com/pion/rtp"
-	"github.com/pion/transport/packetio"
+	"github.com/pion/transport/v2/packetio"
 )
 
 // Limit the buffer size to 1MB
diff --git a/stream_srtp_test.go b/stream_srtp_test.go
index 9b09118..3888f8a 100644
--- a/stream_srtp_test.go
+++ b/stream_srtp_test.go
@@ -8,7 +8,7 @@ import (
 	"time"
 
 	"github.com/pion/rtp"
-	"github.com/pion/transport/packetio"
+	"github.com/pion/transport/v2/packetio"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -202,7 +202,7 @@ func BenchmarkWriteRTP(b *testing.B) {
 	b.Run("CTR-100", func(b *testing.B) {
 		benchmarkWriteRTP(b, profileCTR, 100)
 	})
-	b.Run("CTR-1400", func(b *testing.B) {
+	b.Run("CTR-1000", func(b *testing.B) {
 		benchmarkWriteRTP(b, profileCTR, 1000)
 	})
 	b.Run("GCM-100", func(b *testing.B) {

More details

Full run details

Historical runs