diff --git a/trunk/3rdparty/srs-bench/gb28181/h265reader.go b/trunk/3rdparty/srs-bench/gb28181/h265reader.go
index 9073c5c32..d90cb0bbf 100644
--- a/trunk/3rdparty/srs-bench/gb28181/h265reader.go
+++ b/trunk/3rdparty/srs-bench/gb28181/h265reader.go
@@ -1,226 +1,50 @@
-// Package h265reader implements a H265 Annex-B Reader
+// Package gb28181 provides GB28181 protocol support
package gb28181
import (
- "bytes"
- "errors"
"io"
+
+ "github.com/pion/webrtc/v4/pkg/media/h265reader"
)
-type NalUnitType uint8
+// Type aliases for compatibility with existing code
+type H265Reader = h265reader.H265Reader
+type NAL = h265reader.NAL
+type NalUnitType = h265reader.NalUnitType
-// Enums for NalUnitTypes
+// NAL unit type constants for compatibility with existing code
const (
- NaluTypeSliceTrailN NalUnitType = 0 // 0x0
- NaluTypeSliceTrailR NalUnitType = 1 // 0x01
- NaluTypeSliceTsaN NalUnitType = 2 // 0x02
- NaluTypeSliceTsaR NalUnitType = 3 // 0x03
- NaluTypeSliceStsaN NalUnitType = 4 // 0x04
- NaluTypeSliceStsaR NalUnitType = 5 // 0x05
- NaluTypeSliceRadlN NalUnitType = 6 // 0x06
- NaluTypeSliceRadlR NalUnitType = 7 // 0x07
- NaluTypeSliceRaslN NalUnitType = 8 // 0x06
- NaluTypeSliceRaslR NalUnitType = 9 // 0x09
+ NaluTypeSliceTrailN = h265reader.NalUnitTypeTrailN
+ NaluTypeSliceTrailR = h265reader.NalUnitTypeTrailR
+ NaluTypeSliceTsaN = h265reader.NalUnitTypeTsaN
+ NaluTypeSliceTsaR = h265reader.NalUnitTypeTsaR
+ NaluTypeSliceStsaN = h265reader.NalUnitTypeStsaN
+ NaluTypeSliceStsaR = h265reader.NalUnitTypeStsaR
+ NaluTypeSliceRadlN = h265reader.NalUnitTypeRadlN
+ NaluTypeSliceRadlR = h265reader.NalUnitTypeRadlR
+ NaluTypeSliceRaslN = h265reader.NalUnitTypeRaslN
+ NaluTypeSliceRaslR = h265reader.NalUnitTypeRaslR
- NaluTypeSliceBlaWlp NalUnitType = 16 // 0x10
- NaluTypeSliceBlaWradl NalUnitType = 17 // 0x11
- NaluTypeSliceBlaNlp NalUnitType = 18 // 0x12
- NaluTypeSliceIdr NalUnitType = 19 // 0x13
- NaluTypeSliceIdrNlp NalUnitType = 20 // 0x14
- NaluTypeSliceCranut NalUnitType = 21 // 0x15
- NaluTypeSliceRsvIrapVcl22 NalUnitType = 22 // 0x16
- NaluTypeSliceRsvIrapVcl23 NalUnitType = 23 // 0x17
+ NaluTypeSliceBlaWlp = h265reader.NalUnitTypeBlaWLp
+ NaluTypeSliceBlaWradl = h265reader.NalUnitTypeBlaWRadl
+ NaluTypeSliceBlaNlp = h265reader.NalUnitTypeBlaNLp
+ NaluTypeSliceIdr = h265reader.NalUnitTypeIdrWRadl
+ NaluTypeSliceIdrNlp = h265reader.NalUnitTypeIdrNLp
+ NaluTypeSliceCranut = h265reader.NalUnitTypeCraNut
+ NaluTypeSliceRsvIrapVcl22 = h265reader.NalUnitTypeReserved41 // Approximate mapping
+ NaluTypeSliceRsvIrapVcl23 = h265reader.NalUnitTypeReserved47 // Approximate mapping
- NaluTypeVps NalUnitType = 32 // 0x20
- NaluTypeSps NalUnitType = 33 // 0x21
- NaluTypePps NalUnitType = 34 // 0x22
- NaluTypeAud NalUnitType = 35 // 0x23
- NaluTypeSei NalUnitType = 39 // 0x27
- NaluTypeSeiSuffix NalUnitType = 40 // 0x28
+ NaluTypeVps = h265reader.NalUnitTypeVps
+ NaluTypeSps = h265reader.NalUnitTypeSps
+ NaluTypePps = h265reader.NalUnitTypePps
+ NaluTypeAud = h265reader.NalUnitTypeAud
+ NaluTypeSei = h265reader.NalUnitTypePrefixSei
+ NaluTypeSeiSuffix = h265reader.NalUnitTypeSuffixSei
- NaluTypeUnspecified NalUnitType = 48 // 0x30
+ NaluTypeUnspecified = h265reader.NalUnitTypeUnspec48
)
-// H265Reader reads data from stream and constructs h265 nal units
-type H265Reader struct {
- stream io.Reader
- nalBuffer []byte
- countOfConsecutiveZeroBytes int
- nalPrefixParsed bool
- readBuffer []byte
-}
-
-var (
- errNilReader = errors.New("stream is nil")
- errDataIsNotH265Stream = errors.New("data is not a H265 bitstream")
-)
-
-// NewReader creates new H265Reader
+// NewReader creates new H265Reader using Pion's implementation
func NewReader(in io.Reader) (*H265Reader, error) {
- if in == nil {
- return nil, errNilReader
- }
-
- reader := &H265Reader{
- stream: in,
- nalBuffer: make([]byte, 0),
- nalPrefixParsed: false,
- readBuffer: make([]byte, 0),
- }
-
- return reader, nil
-}
-
-// NAL H.265 Network Abstraction Layer
-type NAL struct {
- PictureOrderCount uint32
-
- // NAL header
- ForbiddenZeroBit bool
- UnitType NalUnitType
- NuhLayerId uint8
- NuhTemporalIdPlus1 uint8
-
- Data []byte // header byte + rbsp
-}
-
-func (reader *H265Reader) read(numToRead int) (data []byte) {
- for len(reader.readBuffer) < numToRead {
- buf := make([]byte, 4096)
- n, err := reader.stream.Read(buf)
- if n == 0 || err != nil {
- break
- }
- buf = buf[0:n]
- reader.readBuffer = append(reader.readBuffer, buf...)
- }
- var numShouldRead int
- if numToRead <= len(reader.readBuffer) {
- numShouldRead = numToRead
- } else {
- numShouldRead = len(reader.readBuffer)
- }
- data = reader.readBuffer[0:numShouldRead]
- reader.readBuffer = reader.readBuffer[numShouldRead:]
- return data
-}
-
-func (reader *H265Reader) bitStreamStartsWithH265Prefix() (prefixLength int, e error) {
- nalPrefix3Bytes := []byte{0, 0, 1}
- nalPrefix4Bytes := []byte{0, 0, 0, 1}
-
- prefixBuffer := reader.read(4)
-
- n := len(prefixBuffer)
-
- if n == 0 {
- return 0, io.EOF
- }
-
- if n < 3 {
- return 0, errDataIsNotH265Stream
- }
-
- nalPrefix3BytesFound := bytes.Equal(nalPrefix3Bytes, prefixBuffer[:3])
- if n == 3 {
- if nalPrefix3BytesFound {
- return 0, io.EOF
- }
- return 0, errDataIsNotH265Stream
- }
-
- // n == 4
- if nalPrefix3BytesFound {
- reader.nalBuffer = append(reader.nalBuffer, prefixBuffer[3])
- return 3, nil
- }
-
- nalPrefix4BytesFound := bytes.Equal(nalPrefix4Bytes, prefixBuffer)
- if nalPrefix4BytesFound {
- return 4, nil
- }
- return 0, errDataIsNotH265Stream
-}
-
-// NextNAL reads from stream and returns then next NAL,
-// and an error if there is incomplete frame data.
-// Returns all nil values when no more NALs are available.
-func (reader *H265Reader) NextNAL() (*NAL, error) {
- if !reader.nalPrefixParsed {
- _, err := reader.bitStreamStartsWithH265Prefix()
- if err != nil {
- return nil, err
- }
-
- reader.nalPrefixParsed = true
- }
-
- for {
- buffer := reader.read(1)
- n := len(buffer)
-
- if n != 1 {
- break
- }
- readByte := buffer[0]
- nalFound := reader.processByte(readByte)
- if nalFound {
- nal := newNal(reader.nalBuffer)
- nal.parseHeader()
- if nal.UnitType == NaluTypeSeiSuffix || nal.UnitType == NaluTypeSei {
- reader.nalBuffer = nil
- continue
- } else {
- break
- }
- }
-
- reader.nalBuffer = append(reader.nalBuffer, readByte)
- }
-
- if len(reader.nalBuffer) == 0 {
- return nil, io.EOF
- }
-
- nal := newNal(reader.nalBuffer)
- reader.nalBuffer = nil
- nal.parseHeader()
-
- return nal, nil
-}
-
-func (reader *H265Reader) processByte(readByte byte) (nalFound bool) {
- nalFound = false
-
- switch readByte {
- case 0:
- reader.countOfConsecutiveZeroBytes++
- case 1:
- if reader.countOfConsecutiveZeroBytes >= 2 {
- countOfConsecutiveZeroBytesInPrefix := 2
- if reader.countOfConsecutiveZeroBytes > 2 {
- countOfConsecutiveZeroBytesInPrefix = 3
- }
- nalUnitLength := len(reader.nalBuffer) - countOfConsecutiveZeroBytesInPrefix
- reader.nalBuffer = reader.nalBuffer[0:nalUnitLength]
- reader.countOfConsecutiveZeroBytes = 0
- nalFound = true
- } else {
- reader.countOfConsecutiveZeroBytes = 0
- }
- default:
- reader.countOfConsecutiveZeroBytes = 0
- }
-
- return nalFound
-}
-
-func newNal(data []byte) *NAL {
- return &NAL{PictureOrderCount: 0, ForbiddenZeroBit: false, UnitType: NaluTypeUnspecified, Data: data}
-}
-
-func (h *NAL) parseHeader() {
- firstByte := h.Data[0]
- h.ForbiddenZeroBit = (((firstByte & 0x80) >> 7) == 1) // 0x80 = 0b10000000
- h.UnitType = NalUnitType((firstByte & 0x7E) >> 1) // 0x1F = 0b01111110
+ return h265reader.NewReader(in)
}
diff --git a/trunk/3rdparty/srs-bench/gb28181/ingester.go b/trunk/3rdparty/srs-bench/gb28181/ingester.go
index 87d9752dc..9870607db 100644
--- a/trunk/3rdparty/srs-bench/gb28181/ingester.go
+++ b/trunk/3rdparty/srs-bench/gb28181/ingester.go
@@ -456,13 +456,13 @@ func (v *PSIngester) writeH265(ctx context.Context, pack *PSPackStream, h265 *H2
videoFrames = append(videoFrames, frame)
logger.If(ctx, "NALU %v PictureOrderCount=%v, ForbiddenZeroBit=%v, %v bytes",
- frame.UnitType, frame.PictureOrderCount, frame.ForbiddenZeroBit, len(frame.Data))
+ frame.NalUnitType, frame.PictureOrderCount, frame.ForbiddenZeroBit, len(frame.Data))
- if frame.UnitType == NaluTypeVps {
+ if frame.NalUnitType == NaluTypeVps {
vps = frame
- } else if frame.UnitType == NaluTypeSps {
+ } else if frame.NalUnitType == NaluTypeSps {
sps = frame
- } else if frame.UnitType == NaluTypePps {
+ } else if frame.NalUnitType == NaluTypePps {
pps = frame
} else {
break
diff --git a/trunk/3rdparty/srs-bench/go.mod b/trunk/3rdparty/srs-bench/go.mod
index d762e6f52..176db4483 100644
--- a/trunk/3rdparty/srs-bench/go.mod
+++ b/trunk/3rdparty/srs-bench/go.mod
@@ -1,6 +1,6 @@
module github.com/ossrs/srs-bench
-go 1.21
+go 1.23.0
require (
github.com/ghettovoice/gosip v0.0.0-20220929080231-de8ba881be83
@@ -8,13 +8,13 @@ require (
github.com/haivision/srtgo v0.0.0-20230627061225-a70d53fcd618
github.com/ossrs/go-oryx-lib v0.0.9
github.com/pion/ice/v4 v4.0.10
- github.com/pion/interceptor v0.1.37
- github.com/pion/logging v0.2.3
+ github.com/pion/interceptor v0.1.40
+ github.com/pion/logging v0.2.4
github.com/pion/rtcp v1.2.15
- github.com/pion/rtp v1.8.15
- github.com/pion/sdp/v3 v3.0.11
+ github.com/pion/rtp v1.8.20
+ github.com/pion/sdp/v3 v3.0.14
github.com/pion/transport/v3 v3.0.7
- github.com/pion/webrtc/v4 v4.1.1
+ github.com/pion/webrtc/v4 v4.1.3
github.com/pkg/errors v0.9.1
github.com/yapingcat/gomedia/codec v0.0.0-20220617074658-94762898dc25
github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
@@ -35,16 +35,16 @@ require (
github.com/pion/mdns/v2 v2.0.7 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/sctp v1.8.39 // indirect
- github.com/pion/srtp/v3 v3.0.4 // indirect
+ github.com/pion/srtp/v3 v3.0.6 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
- github.com/pion/turn/v4 v4.0.0 // indirect
+ github.com/pion/turn/v4 v4.0.2 // indirect
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b // indirect
github.com/sirupsen/logrus v1.4.2 // indirect
github.com/tevino/abool v0.0.0-20170917061928-9b9efcf221b5 // indirect
github.com/wlynxg/anet v0.0.5 // indirect
github.com/x-cray/logrus-prefixed-formatter v0.5.2 // indirect
- golang.org/x/crypto v0.33.0 // indirect
- golang.org/x/net v0.35.0 // indirect
- golang.org/x/sys v0.30.0 // indirect
- golang.org/x/term v0.29.0 // indirect
+ golang.org/x/crypto v0.39.0 // indirect
+ golang.org/x/net v0.41.0 // indirect
+ golang.org/x/sys v0.33.0 // indirect
+ golang.org/x/term v0.32.0 // indirect
)
diff --git a/trunk/3rdparty/srs-bench/go.sum b/trunk/3rdparty/srs-bench/go.sum
index 6ace3527b..0872ce64e 100644
--- a/trunk/3rdparty/srs-bench/go.sum
+++ b/trunk/3rdparty/srs-bench/go.sum
@@ -65,32 +65,32 @@ github.com/pion/dtls/v3 v3.0.6 h1:7Hkd8WhAJNbRgq9RgdNh1aaWlZlGpYTzdqjy9x9sK2E=
github.com/pion/dtls/v3 v3.0.6/go.mod h1:iJxNQ3Uhn1NZWOMWlLxEEHAN5yX7GyPvvKw04v9bzYU=
github.com/pion/ice/v4 v4.0.10 h1:P59w1iauC/wPk9PdY8Vjl4fOFL5B+USq1+xbDcN6gT4=
github.com/pion/ice/v4 v4.0.10/go.mod h1:y3M18aPhIxLlcO/4dn9X8LzLLSma84cx6emMSu14FGw=
-github.com/pion/interceptor v0.1.37 h1:aRA8Zpab/wE7/c0O3fh1PqY0AJI3fCSEM5lRWJVorwI=
-github.com/pion/interceptor v0.1.37/go.mod h1:JzxbJ4umVTlZAf+/utHzNesY8tmRkM2lVmkS82TTj8Y=
-github.com/pion/logging v0.2.3 h1:gHuf0zpoh1GW67Nr6Gj4cv5Z9ZscU7g/EaoC/Ke/igI=
-github.com/pion/logging v0.2.3/go.mod h1:z8YfknkquMe1csOrxK5kc+5/ZPAzMxbKLX5aXpbpC90=
+github.com/pion/interceptor v0.1.40 h1:e0BjnPcGpr2CFQgKhrQisBU7V3GXK6wrfYrGYaU6Jq4=
+github.com/pion/interceptor v0.1.40/go.mod h1:Z6kqH7M/FYirg3frjGJ21VLSRJGBXB/KqaTIrdqnOic=
+github.com/pion/logging v0.2.4 h1:tTew+7cmQ+Mc1pTBLKH2puKsOvhm32dROumOZ655zB8=
+github.com/pion/logging v0.2.4/go.mod h1:DffhXTKYdNZU+KtJ5pyQDjvOAh/GsNSyv1lbkFbe3so=
github.com/pion/mdns/v2 v2.0.7 h1:c9kM8ewCgjslaAmicYMFQIde2H9/lrZpjBkN8VwoVtM=
github.com/pion/mdns/v2 v2.0.7/go.mod h1:vAdSYNAT0Jy3Ru0zl2YiW3Rm/fJCwIeM0nToenfOJKA=
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.15 h1:LZQi2JbdipLOj4eBjK4wlVoQWfrZbh3Q6eHtWtJBZBo=
github.com/pion/rtcp v1.2.15/go.mod h1:jlGuAjHMEXwMUHK78RgX0UmEJFV4zUKOFHR7OP+D3D0=
-github.com/pion/rtp v1.8.15 h1:MuhuGn1cxpVCPLNY1lI7F1tQ8Spntpgf12ob+pOYT8s=
-github.com/pion/rtp v1.8.15/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
+github.com/pion/rtp v1.8.20 h1:8zcyqohadZE8FCBeGdyEvHiclPIezcwRQH9zfapFyYI=
+github.com/pion/rtp v1.8.20/go.mod h1:bAu2UFKScgzyFqvUKmbvzSdPr+NGbZtv6UB2hesqXBk=
github.com/pion/sctp v1.8.39 h1:PJma40vRHa3UTO3C4MyeJDQ+KIobVYRZQZ0Nt7SjQnE=
github.com/pion/sctp v1.8.39/go.mod h1:cNiLdchXra8fHQwmIoqw0MbLLMs+f7uQ+dGMG2gWebE=
-github.com/pion/sdp/v3 v3.0.11 h1:VhgVSopdsBKwhCFoyyPmT1fKMeV9nLMrEKxNOdy3IVI=
-github.com/pion/sdp/v3 v3.0.11/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
-github.com/pion/srtp/v3 v3.0.4 h1:2Z6vDVxzrX3UHEgrUyIGM4rRouoC7v+NiF1IHtp9B5M=
-github.com/pion/srtp/v3 v3.0.4/go.mod h1:1Jx3FwDoxpRaTh1oRV8A/6G1BnFL+QI82eK4ms8EEJQ=
+github.com/pion/sdp/v3 v3.0.14 h1:1h7gBr9FhOWH5GjWWY5lcw/U85MtdcibTyt/o6RxRUI=
+github.com/pion/sdp/v3 v3.0.14/go.mod h1:88GMahN5xnScv1hIMTqLdu/cOcUkj6a9ytbncwMCq2E=
+github.com/pion/srtp/v3 v3.0.6 h1:E2gyj1f5X10sB/qILUGIkL4C2CqK269Xq167PbGCc/4=
+github.com/pion/srtp/v3 v3.0.6/go.mod h1:BxvziG3v/armJHAaJ87euvkhHqWe9I7iiOy50K2QkhY=
github.com/pion/stun/v3 v3.0.0 h1:4h1gwhWLWuZWOJIJR9s2ferRO+W3zA/b6ijOI6mKzUw=
github.com/pion/stun/v3 v3.0.0/go.mod h1:HvCN8txt8mwi4FBvS3EmDghW6aQJ24T+y+1TKjB5jyU=
github.com/pion/transport/v3 v3.0.7 h1:iRbMH05BzSNwhILHoBoAPxoB9xQgOaJk+591KC9P1o0=
github.com/pion/transport/v3 v3.0.7/go.mod h1:YleKiTZ4vqNxVwh77Z0zytYi7rXHl7j6uPLGhhz9rwo=
-github.com/pion/turn/v4 v4.0.0 h1:qxplo3Rxa9Yg1xXDxxH8xaqcyGUtbHYw4QSCvmFWvhM=
-github.com/pion/turn/v4 v4.0.0/go.mod h1:MuPDkm15nYSklKpN8vWJ9W2M0PlyQZqYt1McGuxG7mA=
-github.com/pion/webrtc/v4 v4.1.1 h1:PMFPtLg1kpD2pVtun+LGUzA3k54JdFl87WO0Z1+HKug=
-github.com/pion/webrtc/v4 v4.1.1/go.mod h1:cgEGkcpxGkT6Di2ClBYO5lP9mFXbCfEOrkYUpjjCQO4=
+github.com/pion/turn/v4 v4.0.2 h1:ZqgQ3+MjP32ug30xAbD6Mn+/K4Sxi3SdNOTFf+7mpps=
+github.com/pion/turn/v4 v4.0.2/go.mod h1:pMMKP/ieNAG/fN5cZiN4SDuyKsXtNTr0ccN7IToA1zs=
+github.com/pion/webrtc/v4 v4.1.3 h1:YZ67Boj9X/hk190jJZ8+HFGQ6DqSZ/fYP3sLAZv7c3c=
+github.com/pion/webrtc/v4 v4.1.3/go.mod h1:rsq+zQ82ryfR9vbb0L1umPJ6Ogq7zm8mcn9fcGnxomM=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -117,8 +117,8 @@ github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25/go.mod h1:
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus=
-golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M=
+golang.org/x/crypto v0.39.0 h1:SHs+kF4LP+f+p14esP5jAoDpHU8Gu/v9lFRK6IT5imM=
+golang.org/x/crypto v0.39.0/go.mod h1:L+Xg3Wf6HoL4Bn4238Z6ft6KfEpN0tJGo53AAPC632U=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -126,8 +126,8 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
-golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
-golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
+golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
+golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -144,15 +144,15 @@ golang.org/x/sys v0.0.0-20200926100807-9d91bd62050c/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201207223542-d4d67f95c62d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201214095126-aec9a390925b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
-golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/term v0.29.0 h1:L6pJp37ocefwRRtYPKSWOWzOtWSxVajvz2ldH/xi3iU=
-golang.org/x/term v0.29.0/go.mod h1:6bl4lRlvVuDgSf3179VpIxBF0o10JUpXWOnI7nErv7s=
+golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
+golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/term v0.32.0 h1:DR4lr0TjUs3epypdhTOkMmuF5CDFJ/8pOnbzMZPQ7bg=
+golang.org/x/term v0.32.0/go.mod h1:uZG1FhGx848Sqfsq4/DlJr3xGGsYMu/L5GW4abiaEPQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
-golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
+golang.org/x/text v0.26.0 h1:P42AVeLghgTYr4+xUnTRKDMqpar+PtX7KWuNQL21L8M=
+golang.org/x/text v0.26.0/go.mod h1:QK15LZJUUQVJxhz7wXgxSy/CJaTFjd0G+YLonydOVQA=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/trunk/3rdparty/srs-bench/srs/rtmp_test.go b/trunk/3rdparty/srs-bench/srs/rtmp_test.go
index 5f93671ba..9dd38da0a 100644
--- a/trunk/3rdparty/srs-bench/srs/rtmp_test.go
+++ b/trunk/3rdparty/srs-bench/srs/rtmp_test.go
@@ -102,7 +102,7 @@ func TestRtmpPublishPlay(t *testing.T) {
}
}
-func TestRtmpPublish_RtcPlay(t *testing.T) {
+func TestRtmpPublish_RtcPlay_AVC(t *testing.T) {
ctx := logger.WithContext(context.Background())
ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
@@ -119,10 +119,11 @@ func TestRtmpPublish_RtcPlay(t *testing.T) {
return err
}
- // Setup the RTC player.
+ // Setup the RTC player with AVC codec support.
var thePlayer *testPlayer
if thePlayer, err = newTestPlayer(registerMiniCodecs, func(play *testPlayer) error {
play.streamSuffix = streamSuffix
+ play.streamCodec = "h264"
var nnPlayReadRTP uint64
return play.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
@@ -234,7 +235,7 @@ func TestRtmpPublish_MultipleSequences(t *testing.T) {
}
// Ingore the duplicated sps/pps.
- if IsAvccrEquals(previousAvccr, avccr) {
+ if isAvccrEquals(previousAvccr, avccr) {
return nil
}
previousAvccr = avccr
@@ -316,7 +317,7 @@ func TestRtmpPublish_MultipleSequences_RtcPlay(t *testing.T) {
return nn, attr, err
}
- annexb, nalus, err := DemuxRtpSpsPps(payload[:nn])
+ annexb, nalus, err := demuxRtpSpsPps(payload[:nn])
if err != nil || len(nalus) == 0 ||
(nalus[0].NALUType != avc.NALUTypeSPS && nalus[0].NALUType != avc.NALUTypePPS) ||
bytes.Equal(annexb, previousSpsPps) {
@@ -640,3 +641,95 @@ func TestRtmpPublish_HttpFlvPlayNoVideo(t *testing.T) {
t.Errorf("err %+v", err)
}
}
+
+// TestRtmpPublish_RtcPlay_HEVC tests HEVC support in RTMP to RTC pipeline (PR 4289)
+// This test publishes H.265 video via RTMP and plays it back via WebRTC with codec=hevc
+func TestRtmpPublish_RtcPlay_HEVC(t *testing.T) {
+ ctx := logger.WithContext(context.Background())
+ ctx, cancel := context.WithTimeout(ctx, time.Duration(*srsTimeout)*time.Millisecond)
+
+ var r0, r1 error
+ err := func() (err error) {
+ streamSuffix := fmt.Sprintf("rtmp-hevc-regression-%v-%v", os.Getpid(), rand.Int())
+ rtmpUrl := fmt.Sprintf("%v://%v%v-%v", srsSchema, *srsServer, *srsStream, streamSuffix)
+
+ // Publisher connect to a RTMP stream.
+ publisher := NewRTMPPublisher()
+ defer publisher.Close()
+
+ if err := publisher.Publish(ctx, rtmpUrl); err != nil {
+ return err
+ }
+
+ // Setup the RTC player with HEVC codec support.
+ var thePlayer *testPlayer
+ if thePlayer, err = newTestPlayer(registerHEVCCodecs, func(play *testPlayer) error {
+ play.streamSuffix = streamSuffix
+ play.streamCodec = "hevc"
+ var nnPlayReadRTP uint64
+ return play.Setup(*srsVnetClientIP, func(api *testWebRTCAPI) {
+ api.registry.Add(newRTPInterceptor(func(i *rtpInterceptor) {
+ i.rtpReader = func(payload []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
+ nn, attr, err := i.nextRTPReader.Read(payload, attributes)
+ if err != nil {
+ return nn, attr, err
+ }
+
+ if nnPlayReadRTP++; nnPlayReadRTP >= uint64(*srsPlayOKPackets) {
+ cancel() // Completed.
+ }
+ logger.Tf(ctx, "Play RECV RTP #%v %vB", nnPlayReadRTP, nn)
+ return nn, attr, err
+ }
+ }))
+ })
+ }); err != nil {
+ return err
+ }
+ defer thePlayer.Close()
+
+ // Run publisher and players.
+ var wg sync.WaitGroup
+ defer wg.Wait()
+
+ var playerIceReady context.Context
+ playerIceReady, thePlayer.iceReadyCancel = context.WithCancel(ctx)
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ if r1 = thePlayer.Run(logger.WithContext(ctx), cancel); r1 != nil {
+ cancel()
+ }
+ logger.Tf(ctx, "player done")
+ }()
+
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ // Wait for player ready.
+ select {
+ case <-ctx.Done():
+ return
+ case <-playerIceReady.Done():
+ }
+
+ publisher.onSendPacket = func(m *rtmp.Message) error {
+ time.Sleep(100 * time.Microsecond)
+ return nil
+ }
+ // Use H.265 file directly without ffmpeg transcoding, implementing new h265 demuxer
+ // in RTMPPublisher using pion pkg/media/h265reader with enhanced-RTMP fourcc 'hvc1'
+ if r0 = publisher.Ingest(ctx, *srsPublishVideoH265); r0 != nil {
+ cancel()
+ }
+ logger.Tf(ctx, "publisher done")
+ }()
+
+ return nil
+ }()
+ if err := filterTestError(ctx.Err(), err, r0, r1); err != nil {
+ t.Errorf("err %+v", err)
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/srs/util.go b/trunk/3rdparty/srs-bench/srs/util.go
index 7836bf701..eb60286a2 100644
--- a/trunk/3rdparty/srs-bench/srs/util.go
+++ b/trunk/3rdparty/srs-bench/srs/util.go
@@ -61,6 +61,7 @@ import (
"github.com/pion/transport/v3/vnet"
"github.com/pion/webrtc/v4"
"github.com/pion/webrtc/v4/pkg/media/h264reader"
+ "github.com/pion/webrtc/v4/pkg/media/h265reader"
)
var srsHttps *bool
@@ -80,6 +81,7 @@ var srsStream *string
var srsLiveStream *string
var srsPublishAudio *string
var srsPublishVideo *string
+var srsPublishVideoH265 *string
var srsPublishAvatar *string
var srsPublishBBB *string
var srsVnetClientIP *string
@@ -97,6 +99,7 @@ func prepareTest() (err error) {
srsPublishOKPackets = flag.Int("srs-publish-ok-packets", 3, "If send N RTP, recv N RTCP packets, it's ok, or fail")
srsPublishAudio = flag.String("srs-publish-audio", "avatar.ogg", "The audio file for publisher.")
srsPublishVideo = flag.String("srs-publish-video", "avatar.h264", "The video file for publisher.")
+ srsPublishVideoH265 = flag.String("srs-publish-video-h265", "avatar.h265", "The H.265 video file for publisher.")
srsPublishAvatar = flag.String("srs-publish-avatar", "avatar.flv", "The avatar file for publisher.")
srsPublishBBB = flag.String("srs-publish-bbb", "bbb.flv", "The bbb file for publisher.")
srsPublishVideoFps = flag.Int("srs-publish-video-fps", 25, "The video fps for publisher.")
@@ -143,6 +146,10 @@ func prepareTest() (err error) {
return err
}
+ if *srsPublishVideoH265, err = tryOpenFile(*srsPublishVideoH265); err != nil {
+ return err
+ }
+
if *srsPublishAvatar, err = tryOpenFile(*srsPublishAvatar); err != nil {
return err
}
@@ -633,16 +640,28 @@ func registerMiniCodecs(api *testWebRTCAPI) error {
v := api
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeOpus, 48000, 2, "minptime=10;useinbandfec=1", nil},
- PayloadType: 111,
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2,
+ SDPFmtpLine: "minptime=10;useinbandfec=1", RTCPFeedback: nil,
+ },
+ PayloadType: 111,
}, webrtc.RTPCodecTypeAudio); err != nil {
return err
}
- videoRTCPFeedback := []webrtc.RTCPFeedback{{"goog-remb", ""}, {"ccm", "fir"}, {"nack", ""}, {"nack", "pli"}}
+ videoRTCPFeedback := []webrtc.RTCPFeedback{
+ {Type: "goog-remb", Parameter: ""},
+ {Type: "ccm", Parameter: "fir"},
+ {Type: "nack", Parameter: ""},
+ {Type: "nack", Parameter: "pli"},
+ }
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f", videoRTCPFeedback},
- PayloadType: 108,
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeH264, ClockRate: 90000, Channels: 0,
+ SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f",
+ RTCPFeedback: videoRTCPFeedback,
+ },
+ PayloadType: 108,
}, webrtc.RTPCodecTypeVideo); err != nil {
return err
}
@@ -656,16 +675,26 @@ func registerMiniCodecsWithoutNack(api *testWebRTCAPI) error {
v := api
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeOpus, 48000, 2, "minptime=10;useinbandfec=1", nil},
- PayloadType: 111,
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2,
+ SDPFmtpLine: "minptime=10;useinbandfec=1", RTCPFeedback: nil,
+ },
+ PayloadType: 111,
}, webrtc.RTPCodecTypeAudio); err != nil {
return err
}
- videoRTCPFeedback := []webrtc.RTCPFeedback{{"goog-remb", ""}, {"ccm", "fir"}}
+ videoRTCPFeedback := []webrtc.RTCPFeedback{
+ {Type: "goog-remb", Parameter: ""},
+ {Type: "ccm", Parameter: "fir"},
+ }
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeH264, 90000, 0, "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f", videoRTCPFeedback},
- PayloadType: 108,
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeH264, ClockRate: 90000, Channels: 0,
+ SDPFmtpLine: "level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f",
+ RTCPFeedback: videoRTCPFeedback,
+ },
+ PayloadType: 108,
}, webrtc.RTPCodecTypeVideo); err != nil {
return err
}
@@ -680,17 +709,28 @@ func registerHEVCCodecs(api *testWebRTCAPI) error {
// Register Opus audio codec
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeOpus, 48000, 2, "minptime=10;useinbandfec=1", nil},
- PayloadType: 111,
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeOpus, ClockRate: 48000, Channels: 2,
+ SDPFmtpLine: "minptime=10;useinbandfec=1", RTCPFeedback: nil,
+ },
+ PayloadType: 111,
}, webrtc.RTPCodecTypeAudio); err != nil {
return err
}
// Register HEVC/H.265 video codec
- videoRTCPFeedback := []webrtc.RTCPFeedback{{"goog-remb", ""}, {"ccm", "fir"}, {"nack", ""}, {"nack", "pli"}}
+ videoRTCPFeedback := []webrtc.RTCPFeedback{
+ {Type: "goog-remb", Parameter: ""},
+ {Type: "ccm", Parameter: "fir"},
+ {Type: "nack", Parameter: ""},
+ {Type: "nack", Parameter: "pli"},
+ }
if err := v.mediaEngine.RegisterCodec(webrtc.RTPCodecParameters{
- RTPCodecCapability: webrtc.RTPCodecCapability{webrtc.MimeTypeH265, 90000, 0, "profile-id=1", videoRTCPFeedback},
- PayloadType: 49, // Use payload type 49 for HEVC as mentioned in PR description
+ RTPCodecCapability: webrtc.RTPCodecCapability{
+ MimeType: webrtc.MimeTypeH265, ClockRate: 90000, Channels: 0,
+ SDPFmtpLine: "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST", RTCPFeedback: videoRTCPFeedback,
+ },
+ PayloadType: 49, // Use payload type 49 for HEVC as mentioned in PR description
}, webrtc.RTPCodecTypeVideo); err != nil {
return err
}
@@ -812,6 +852,8 @@ type testPlayer struct {
api *testWebRTCAPI
// Optional suffix for stream url.
streamSuffix string
+ // Optional codec for stream, e.g., "hevc", "h264".
+ streamCodec string
// Optional app/stream to play, use srsStream by default.
defaultStream string
}
@@ -864,6 +906,13 @@ func (v *testPlayer) Run(ctx context.Context, cancel context.CancelFunc) error {
if v.streamSuffix != "" {
r = fmt.Sprintf("%v-%v", r, v.streamSuffix)
}
+ if v.streamCodec != "" {
+ if strings.Contains(r, "?") {
+ r = fmt.Sprintf("%v&codec=%v", r, v.streamCodec)
+ } else {
+ r = fmt.Sprintf("%v?codec=%v", r, v.streamCodec)
+ }
+ }
pli := time.Duration(*srsPlayPLI) * time.Millisecond
logger.Tf(ctx, "Run play url=%v", r)
@@ -1634,7 +1683,7 @@ func (v *RTMPPublisher) Publish(ctx context.Context, rtmpUrl string) error {
return v.client.Publish(ctx, rtmpUrl)
}
-func (v *RTMPPublisher) Ingest(ctx context.Context, flvInput string) error {
+func (v *RTMPPublisher) Ingest(ctx context.Context, input string) error {
// If ctx is cancelled, close the RTMP transport.
var wg sync.WaitGroup
defer wg.Wait()
@@ -1649,8 +1698,16 @@ func (v *RTMPPublisher) Ingest(ctx context.Context, flvInput string) error {
}()
// Consume all packets.
- logger.Tf(ctx, "Start to ingest %v", flvInput)
- err := v.ingest(ctx, flvInput)
+ logger.Tf(ctx, "Start to ingest %v", input)
+
+ // Check file extension to determine format
+ var err error
+ if strings.HasSuffix(strings.ToLower(input), ".h265") {
+ err = v.ingestH265(ctx, input)
+ } else {
+ // Default to FLV format for H.264
+ err = v.ingestFLV(ctx, input)
+ }
if err == io.EOF {
return nil
}
@@ -1660,7 +1717,7 @@ func (v *RTMPPublisher) Ingest(ctx context.Context, flvInput string) error {
return err
}
-func (v *RTMPPublisher) ingest(ctx context.Context, flvInput string) error {
+func (v *RTMPPublisher) ingestFLV(ctx context.Context, flvInput string) error {
p := v.client
fs, err := os.Open(flvInput)
@@ -1718,6 +1775,247 @@ func (v *RTMPPublisher) ingest(ctx context.Context, flvInput string) error {
return nil
}
+func (v *RTMPPublisher) ingestH265(ctx context.Context, h265Input string) error {
+ p := v.client
+
+ fs, err := os.Open(h265Input)
+ if err != nil {
+ return err
+ }
+ defer fs.Close()
+ logger.Tf(ctx, "Open H.265 input %v", h265Input)
+
+ h265Reader, err := h265reader.NewReader(fs)
+ if err != nil {
+ return err
+ }
+
+ // Send sequence header first
+ var vps, sps, pps []byte
+ var timestamp uint64 = 0
+
+ // Read NALUs to find VPS, SPS, PPS
+ for {
+ nal, err := h265Reader.NextNAL()
+ if err != nil {
+ if err == io.EOF {
+ break
+ }
+ return err
+ }
+
+ if nal == nil {
+ break
+ }
+
+ // Extract parameter sets using pion constants
+ switch nal.NalUnitType {
+ case h265reader.NalUnitTypeVps: // VPS (32)
+ vps = nal.Data
+ case h265reader.NalUnitTypeSps: // SPS (33)
+ sps = nal.Data
+ case h265reader.NalUnitTypePps: // PPS (34)
+ pps = nal.Data
+ }
+
+ // Once we have all parameter sets, send sequence header
+ if len(vps) > 0 && len(sps) > 0 && len(pps) > 0 {
+ if err := v.sendH265SequenceHeader(p, vps, sps, pps, timestamp); err != nil {
+ return err
+ }
+ break
+ }
+ }
+
+ // Reset reader for actual frame data
+ fs.Seek(0, 0)
+ h265Reader, err = h265reader.NewReader(fs)
+ if err != nil {
+ return err
+ }
+
+ // Send video frames
+ frameCount := 0
+ for {
+ select {
+ case <-ctx.Done():
+ return ctx.Err()
+ default:
+ }
+
+ nal, err := h265Reader.NextNAL()
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+
+ if nal == nil {
+ return nil
+ }
+
+ // Skip parameter sets as they were already sent
+ if nal.NalUnitType == h265reader.NalUnitTypeVps || nal.NalUnitType == h265reader.NalUnitTypeSps || nal.NalUnitType == h265reader.NalUnitTypePps {
+ continue
+ }
+
+ // Send video frame - check for IDR and CRA frames (key frames)
+ isKeyFrame := (nal.NalUnitType >= h265reader.NalUnitTypeBlaWLp && nal.NalUnitType <= h265reader.NalUnitTypeCraNut)
+ if err := v.sendH265Frame(p, nal.Data, timestamp, isKeyFrame); err != nil {
+ return err
+ }
+
+ frameCount++
+ timestamp += 40 // 25fps = 40ms per frame
+
+ if v.onSendPacket != nil {
+ m := rtmp.NewStreamMessage(p.streamID)
+ m.MessageType = rtmp.MessageTypeVideo
+ m.Timestamp = timestamp
+ m.Payload = nal.Data
+ if err = v.onSendPacket(m); err != nil {
+ return err
+ }
+ }
+ }
+}
+
+func (v *RTMPPublisher) sendH265SequenceHeader(p *RTMPClient, vps, sps, pps []byte, timestamp uint64) error {
+ // Create HEVC sequence header using enhanced-RTMP format
+ // Format: [IsExHeader | FrameType | PacketType] [fourcc 'hvc1'] [HEVCDecoderConfigurationRecord]
+ // @see: https://veovera.org/docs/enhanced/enhanced-rtmp-v1.pdf, page 9
+
+ const flvIsExHeader = 0x80
+ const videoAvcFrameTypeKeyFrame = 1
+ const videoHEVCFrameTraitPacketTypeSequenceStart = 0
+
+ // IsExHeader | FrameType | PacketType
+ frameTypeAndPacket := byte(flvIsExHeader | (videoAvcFrameTypeKeyFrame << 4) | videoHEVCFrameTraitPacketTypeSequenceStart)
+
+ // Enhanced-RTMP fourcc 'hvc1' for HEVC (0x68766331)
+ fourcc := []byte{'h', 'v', 'c', '1'}
+
+ // Create proper HEVCDecoderConfigurationRecord
+ hvcc := v.createHVCC(vps, sps, pps)
+
+ // Build enhanced-RTMP packet
+ var payload []byte
+ payload = append(payload, frameTypeAndPacket)
+ payload = append(payload, fourcc...)
+ payload = append(payload, hvcc...)
+
+ m := rtmp.NewStreamMessage(p.streamID)
+ m.MessageType = rtmp.MessageTypeVideo
+ m.Timestamp = timestamp
+ m.Payload = payload
+
+ return p.proto.WriteMessage(m)
+}
+
+func (v *RTMPPublisher) createHVCC(vps, sps, pps []byte) []byte {
+ // Create HEVCDecoderConfigurationRecord based on SRS format
+ // @see: trunk/src/protocol/srs_protocol_raw_avc.cpp mux_sequence_header
+
+ var hvcc []byte
+
+ // configuration_version (1 byte) - must be 1
+ hvcc = append(hvcc, 0x01)
+
+ // general_profile_space (2 bits) + general_tier_flag (1 bit) + general_profile_idc (5 bits)
+ hvcc = append(hvcc, 0x01) // simplified: profile_space=0, tier_flag=0, profile_idc=1
+
+ // general_profile_compatibility_flags (4 bytes)
+ hvcc = append(hvcc, 0x60, 0x00, 0x00, 0x00)
+
+ // general_constraint_indicator_flags (6 bytes)
+ hvcc = append(hvcc, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00)
+
+ // general_level_idc (1 byte)
+ hvcc = append(hvcc, 0x5d) // Level 3.1
+
+ // min_spatial_segmentation_idc (12 bits) + reserved (4 bits)
+ hvcc = append(hvcc, 0xf0, 0x00)
+
+ // parallelismType (2 bits) + reserved (6 bits)
+ hvcc = append(hvcc, 0xfc)
+
+ // chromaFormat (2 bits) + reserved (6 bits)
+ hvcc = append(hvcc, 0xfd)
+
+ // bitDepthLumaMinus8 (3 bits) + reserved (5 bits)
+ hvcc = append(hvcc, 0xf8)
+
+ // bitDepthChromaMinus8 (3 bits) + reserved (5 bits)
+ hvcc = append(hvcc, 0xf8)
+
+ // avgFrameRate (2 bytes)
+ hvcc = append(hvcc, 0x00, 0x00)
+
+ // constantFrameRate (2 bits) + numTemporalLayers (3 bits) + temporalIdNested (1 bit) + lengthSizeMinusOne (2 bits)
+ hvcc = append(hvcc, 0x0f) // lengthSizeMinusOne = 3 (4-byte length)
+
+ // numOfArrays (1 byte) - we have 3 arrays: VPS, SPS, PPS
+ hvcc = append(hvcc, 0x03)
+
+ // VPS array
+ hvcc = append(hvcc, 0x20) // array_completeness=0, reserved=0, NAL_unit_type=32 (VPS)
+ hvcc = append(hvcc, 0x00, 0x01) // numNalus = 1
+ hvcc = append(hvcc, byte(len(vps)>>8), byte(len(vps))) // nalUnitLength
+ hvcc = append(hvcc, vps...)
+
+ // SPS array
+ hvcc = append(hvcc, 0x21) // array_completeness=0, reserved=0, NAL_unit_type=33 (SPS)
+ hvcc = append(hvcc, 0x00, 0x01) // numNalus = 1
+ hvcc = append(hvcc, byte(len(sps)>>8), byte(len(sps))) // nalUnitLength
+ hvcc = append(hvcc, sps...)
+
+ // PPS array
+ hvcc = append(hvcc, 0x22) // array_completeness=0, reserved=0, NAL_unit_type=34 (PPS)
+ hvcc = append(hvcc, 0x00, 0x01) // numNalus = 1
+ hvcc = append(hvcc, byte(len(pps)>>8), byte(len(pps))) // nalUnitLength
+ hvcc = append(hvcc, pps...)
+
+ return hvcc
+}
+
+func (v *RTMPPublisher) sendH265Frame(p *RTMPClient, nalData []byte, timestamp uint64, isKeyFrame bool) error {
+ // Create HEVC frame packet using enhanced-RTMP format
+ // Format: [IsExHeader | FrameType | PacketType] [fourcc 'hvc1'] [NALU data]
+ // @see: https://veovera.org/docs/enhanced/enhanced-rtmp-v1.pdf, page 9
+
+ const flvIsExHeader = 0x80
+ const videoAvcFrameTypeKeyFrame = 1
+ const videoAvcFrameTypeInterFrame = 2
+ const videoHEVCFrameTraitPacketTypeCodedFramesX = 3
+
+ var frameType byte = videoAvcFrameTypeInterFrame
+ if isKeyFrame {
+ frameType = videoAvcFrameTypeKeyFrame
+ }
+
+ // IsExHeader | FrameType | PacketType
+ frameTypeAndPacket := byte(flvIsExHeader | (frameType << 4) | videoHEVCFrameTraitPacketTypeCodedFramesX)
+
+ // Enhanced-RTMP fourcc 'hvc1' for HEVC (0x68766331)
+ fourcc := []byte{'h', 'v', 'c', '1'}
+
+ var payload []byte
+ payload = append(payload, frameTypeAndPacket)
+ payload = append(payload, fourcc...)
+
+ // Add NALU length and data (IBMF format)
+ payload = append(payload, byte(len(nalData)>>24), byte(len(nalData)>>16), byte(len(nalData)>>8), byte(len(nalData)))
+ payload = append(payload, nalData...)
+
+ m := rtmp.NewStreamMessage(p.streamID)
+ m.MessageType = rtmp.MessageTypeVideo
+ m.Timestamp = timestamp
+ m.Payload = payload
+
+ return p.proto.WriteMessage(m)
+}
+
type RTMPPlayer struct {
// Transport.
client *RTMPClient
@@ -1922,7 +2220,7 @@ func (v *FLVPlayer) consume(ctx context.Context) (err error) {
}
}
-func IsAvccrEquals(a, b *avc.AVCDecoderConfigurationRecord) bool {
+func isAvccrEquals(a, b *avc.AVCDecoderConfigurationRecord) bool {
if a == nil || b == nil {
return false
}
@@ -1936,13 +2234,13 @@ func IsAvccrEquals(a, b *avc.AVCDecoderConfigurationRecord) bool {
}
for i := 0; i < len(a.SequenceParameterSetNALUnits); i++ {
- if !IsNALUEquals(a.SequenceParameterSetNALUnits[i], b.SequenceParameterSetNALUnits[i]) {
+ if !isNALUEquals(a.SequenceParameterSetNALUnits[i], b.SequenceParameterSetNALUnits[i]) {
return false
}
}
for i := 0; i < len(a.PictureParameterSetNALUnits); i++ {
- if !IsNALUEquals(a.PictureParameterSetNALUnits[i], b.PictureParameterSetNALUnits[i]) {
+ if !isNALUEquals(a.PictureParameterSetNALUnits[i], b.PictureParameterSetNALUnits[i]) {
return false
}
}
@@ -1950,7 +2248,7 @@ func IsAvccrEquals(a, b *avc.AVCDecoderConfigurationRecord) bool {
return true
}
-func IsNALUEquals(a, b *avc.NALU) bool {
+func isNALUEquals(a, b *avc.NALU) bool {
if a == nil || b == nil {
return false
}
@@ -1962,7 +2260,7 @@ func IsNALUEquals(a, b *avc.NALU) bool {
return bytes.Equal(a.Data, b.Data)
}
-func DemuxRtpSpsPps(payload []byte) ([]byte, []*avc.NALU, error) {
+func demuxRtpSpsPps(payload []byte) ([]byte, []*avc.NALU, error) {
// Parse RTP packet.
pkt := rtp.Packet{}
if err := pkt.Unmarshal(payload); err != nil {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
index a3235bec2..120faf29b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/.golangci.yml
@@ -19,23 +19,42 @@ linters-settings:
recommendations:
- errors
forbidigo:
+ analyze-types: true
forbid:
- ^fmt.Print(f|ln)?$
- ^log.(Panic|Fatal|Print)(f|ln)?$
- ^os.Exit$
- ^panic$
- ^print(ln)?$
+ - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$
+ pkg: ^testing$
+ msg: "use testify/assert instead"
+ 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`.
@@ -46,18 +65,17 @@ linters:
- forcetypeassert # finds forced type assertions
- 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 +83,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 +99,22 @@ 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 +122,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!
@@ -114,9 +131,12 @@ issues:
exclude-dirs-use-default: false
exclude-rules:
# Allow complex tests and examples, better to be self contained
- - path: (examples|main\.go|_test\.go)
+ - path: (examples|main\.go)
linters:
+ - gocognit
- forbidigo
+ - path: _test\.go
+ linters:
- gocognit
# Allow forbidden identifiers in CLI commands
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
index 5db5d4414..46a9ca6a2 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/README.md
@@ -3,10 +3,10 @@
Pion Interceptor
-
RTCP and RTCP processors for building real time communications
+RTP and RTCP processors for building real time communications
-
+
@@ -36,12 +36,12 @@ by anyone. With the following tenets in mind.
* [Google Congestion Control](https://github.com/pion/interceptor/tree/master/pkg/gcc)
* [Stats](https://github.com/pion/interceptor/tree/master/pkg/stats) A [webrtc-stats](https://www.w3.org/TR/webrtc-stats/) compliant statistics generation
* [Interval PLI](https://github.com/pion/interceptor/tree/master/pkg/intervalpli) Generate PLI on a interval. Useful when no decoder is available.
+* [FlexFec](https://github.com/pion/interceptor/tree/master/pkg/flexfec) – [FlexFEC-03](https://datatracker.ietf.org/doc/html/draft-ietf-payload-flexible-fec-scheme-03) encoder implementation
### Planned Interceptors
* Bandwidth Estimation
- [NADA](https://tools.ietf.org/html/rfc8698)
* JitterBuffer, re-order packets and wait for arrival
-* [FlexFec](https://tools.ietf.org/html/draft-ietf-payload-flexible-fec-scheme-20)
* [RTCP Feedback for Congestion Control](https://datatracker.ietf.org/doc/html/rfc8888) the standardized alternative to TWCC.
### Interceptor Public API
@@ -70,9 +70,9 @@ You should also look in [pion/webrtc](https://github.com/pion/webrtc) for real w
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Slack](https://pion.ly/slack).
+Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt).
-Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
+Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go
index 8b6d0f5cf..e4257b8da 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/attributes.go
@@ -19,7 +19,7 @@ const (
var errInvalidType = errors.New("found value of invalid type in attributes map")
-// Attributes are a generic key/value store used by interceptors
+// Attributes are a generic key/value store used by interceptors.
type Attributes map[interface{}]interface{}
// Get returns the attribute associated with key.
@@ -39,6 +39,7 @@ func (a Attributes) GetRTPHeader(raw []byte) (*rtp.Header, error) {
if header, ok := val.(*rtp.Header); ok {
return header, nil
}
+
return nil, errInvalidType
}
header := &rtp.Header{}
@@ -46,6 +47,7 @@ func (a Attributes) GetRTPHeader(raw []byte) (*rtp.Header, error) {
return nil, err
}
a[rtpHeaderKey] = header
+
return header, nil
}
@@ -57,6 +59,7 @@ func (a Attributes) GetRTCPPackets(raw []byte) ([]rtcp.Packet, error) {
if packets, ok := val.([]rtcp.Packet); ok {
return packets, nil
}
+
return nil, errInvalidType
}
pkts, err := rtcp.Unmarshal(raw)
@@ -64,5 +67,6 @@ func (a Attributes) GetRTCPPackets(raw []byte) ([]rtcp.Packet, error) {
return nil, err
}
a[rtcpPacketsKey] = pkts
+
return pkts, nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
index 267f36651..62c0aeb12 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/chain.go
@@ -50,7 +50,8 @@ func (i *Chain) UnbindLocalStream(ctx *StreamInfo) {
}
}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
+// BindRemoteStream lets you modify any incoming RTP packets.
+// It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
func (i *Chain) BindRemoteStream(ctx *StreamInfo, reader RTPReader) RTPReader {
for _, interceptor := range i.interceptors {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
index 3dafee3ef..02c79539c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/errors.go
@@ -18,6 +18,7 @@ func flattenErrs(errs []error) error {
if len(errs2) == 0 {
return nil
}
+
return multiError(errs2)
}
@@ -50,5 +51,6 @@ func (me multiError) Is(err error) bool {
}
}
}
+
return false
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
index c6ba53242..10d3e32fc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/interceptor.go
@@ -12,7 +12,7 @@ import (
"github.com/pion/rtp"
)
-// Factory provides an interface for constructing interceptors
+// Factory provides an interface for constructing interceptors.
type Factory interface {
NewInterceptor(id string) (Interceptor, error)
}
@@ -35,7 +35,8 @@ type Interceptor interface {
// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
UnbindLocalStream(info *StreamInfo)
- // BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
+ // BindRemoteStream lets you modify any incoming RTP packets.
+ // It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
BindRemoteStream(info *StreamInfo, reader RTPReader) RTPReader
@@ -69,34 +70,34 @@ type RTCPReader interface {
Read([]byte, Attributes) (int, Attributes, error)
}
-// RTPWriterFunc is an adapter for RTPWrite interface
+// RTPWriterFunc is an adapter for RTPWrite interface.
type RTPWriterFunc func(header *rtp.Header, payload []byte, attributes Attributes) (int, error)
-// RTPReaderFunc is an adapter for RTPReader interface
+// RTPReaderFunc is an adapter for RTPReader interface.
type RTPReaderFunc func([]byte, Attributes) (int, Attributes, error)
-// RTCPWriterFunc is an adapter for RTCPWriter interface
+// RTCPWriterFunc is an adapter for RTCPWriter interface.
type RTCPWriterFunc func(pkts []rtcp.Packet, attributes Attributes) (int, error)
-// RTCPReaderFunc is an adapter for RTCPReader interface
+// RTCPReaderFunc is an adapter for RTCPReader interface.
type RTCPReaderFunc func([]byte, Attributes) (int, Attributes, error)
-// Write a rtp packet
+// Write a rtp packet.
func (f RTPWriterFunc) Write(header *rtp.Header, payload []byte, attributes Attributes) (int, error) {
return f(header, payload, attributes)
}
-// Read a rtp packet
+// Read a rtp packet.
func (f RTPReaderFunc) Read(b []byte, a Attributes) (int, Attributes, error) {
return f(b, a)
}
-// Write a batch of rtcp packets
+// Write a batch of rtcp packets.
func (f RTCPWriterFunc) Write(pkts []rtcp.Packet, attributes Attributes) (int, error) {
return f(pkts, attributes)
}
-// Read a batch of rtcp packets
+// Read a batch of rtcp packets.
func (f RTCPReaderFunc) Read(b []byte, a Attributes) (int, Attributes, error) {
return f(b, a)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go
index 69f98d6c9..266f13d88 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/ntp/ntp.go
@@ -9,7 +9,7 @@ import (
"time"
)
-// ToNTP converts a time.Time oboject to an uint64 NTP timestamp
+// ToNTP converts a time.Time oboject to an uint64 NTP timestamp.
func ToNTP(t time.Time) uint64 {
// seconds since 1st January 1900
s := (float64(t.UnixNano()) / 1000000000) + 2208988800
@@ -17,14 +17,31 @@ func ToNTP(t time.Time) uint64 {
// higher 32 bits are the integer part, lower 32 bits are the fractional part
integerPart := uint32(s)
fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
- return uint64(integerPart)<<32 | uint64(fractionalPart)
+
+ return uint64(integerPart)<<32 | uint64(fractionalPart) //nolint:gosec // G115
}
-// ToTime converts a uint64 NTP timestamps to a time.Time object
+// ToNTP32 converts a time.Time object to a uint32 NTP timestamp.
+func ToNTP32(t time.Time) uint32 {
+ return uint32(ToNTP(t) >> 16) //nolint:gosec // G115
+}
+
+// ToTime converts a uint64 NTP timestamps to a time.Time object.
func ToTime(t uint64) time.Time {
seconds := (t & 0xFFFFFFFF00000000) >> 32
fractional := float64(t&0x00000000FFFFFFFF) / float64(0xFFFFFFFF)
+ //nolint:gosec // G115
d := time.Duration(seconds)*time.Second + time.Duration(fractional*1e9)*time.Nanosecond
return time.Unix(0, 0).Add(-2208988800 * time.Second).Add(d)
}
+
+// ToTime32 converts a uint32 NTP timestamp to a time.Time object, using the
+// highest 16 bit of the reference to recover the lost bits. The low 16 bits are
+// not recovered.
+func ToTime32(t uint32, reference time.Time) time.Time {
+ referenceNTP := ToNTP(reference) & 0xFFFF000000000000
+ tu64 := ((uint64(t) << 16) & 0x0000FFFFFFFF0000) | referenceNTP
+
+ return ToTime(tu64)
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/errors.go
new file mode 100644
index 000000000..4c3112ba2
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/errors.go
@@ -0,0 +1,16 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package rtpbuffer
+
+import "errors"
+
+// ErrInvalidSize is returned by newReceiveLog/newRTPBuffer, when an incorrect buffer size is supplied.
+var ErrInvalidSize = errors.New("invalid buffer size")
+
+var (
+ errPacketReleased = errors.New("could not retain packet, already released")
+ errFailedToCastHeaderPool = errors.New("could not access header pool, failed cast")
+ errFailedToCastPayloadPool = errors.New("could not access payload pool, failed cast")
+ errPaddingOverflow = errors.New("padding size exceeds payload size")
+)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/packet_factory.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/packet_factory.go
new file mode 100644
index 000000000..a9a8d36fb
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/packet_factory.go
@@ -0,0 +1,149 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package rtpbuffer
+
+import (
+ "encoding/binary"
+ "io"
+ "sync"
+
+ "github.com/pion/rtp"
+)
+
+const rtxSsrcByteLength = 2
+
+// PacketFactory allows custom logic around the handle of RTP Packets before they added to the RTPBuffer.
+// The NoOpPacketFactory doesn't copy packets, while the RetainablePacket will take a copy before adding.
+type PacketFactory interface {
+ NewPacket(header *rtp.Header, payload []byte, rtxSsrc uint32, rtxPayloadType uint8) (*RetainablePacket, error)
+}
+
+// PacketFactoryCopy is PacketFactory that takes a copy of packets when added to the RTPBuffer.
+type PacketFactoryCopy struct {
+ headerPool *sync.Pool
+ payloadPool *sync.Pool
+ rtxSequencer rtp.Sequencer
+}
+
+// NewPacketFactoryCopy constructs a PacketFactory that takes a copy of packets when added to the RTPBuffer.
+func NewPacketFactoryCopy() *PacketFactoryCopy {
+ return &PacketFactoryCopy{
+ headerPool: &sync.Pool{
+ New: func() interface{} {
+ return &rtp.Header{}
+ },
+ },
+ payloadPool: &sync.Pool{
+ New: func() interface{} {
+ buf := make([]byte, maxPayloadLen)
+
+ return &buf
+ },
+ },
+ rtxSequencer: rtp.NewRandomSequencer(),
+ }
+}
+
+// NewPacket constructs a new RetainablePacket that can be added to the RTPBuffer.
+//
+//nolint:cyclop
+func (m *PacketFactoryCopy) NewPacket(
+ header *rtp.Header, payload []byte, rtxSsrc uint32, rtxPayloadType uint8,
+) (*RetainablePacket, error) {
+ if len(payload) > maxPayloadLen {
+ return nil, io.ErrShortBuffer
+ }
+
+ retainablePacket := &RetainablePacket{
+ onRelease: m.releasePacket,
+ sequenceNumber: header.SequenceNumber,
+ // new packets have retain count of 1
+ count: 1,
+ }
+
+ var ok bool
+ retainablePacket.header, ok = m.headerPool.Get().(*rtp.Header)
+ if !ok {
+ return nil, errFailedToCastHeaderPool
+ }
+
+ *retainablePacket.header = header.Clone()
+
+ if payload != nil {
+ retainablePacket.buffer, ok = m.payloadPool.Get().(*[]byte)
+ if !ok {
+ return nil, errFailedToCastPayloadPool
+ }
+ if rtxSsrc != 0 && rtxPayloadType != 0 {
+ size := copy((*retainablePacket.buffer)[rtxSsrcByteLength:], payload)
+ retainablePacket.payload = (*retainablePacket.buffer)[:size+rtxSsrcByteLength]
+ } else {
+ size := copy(*retainablePacket.buffer, payload)
+ retainablePacket.payload = (*retainablePacket.buffer)[:size]
+ }
+ }
+
+ if rtxSsrc != 0 && rtxPayloadType != 0 { //nolint:nestif
+ if payload == nil {
+ retainablePacket.buffer, ok = m.payloadPool.Get().(*[]byte)
+ if !ok {
+ return nil, errFailedToCastPayloadPool
+ }
+ retainablePacket.payload = (*retainablePacket.buffer)[:rtxSsrcByteLength]
+ }
+ // Write the original sequence number at the beginning of the payload.
+ binary.BigEndian.PutUint16(retainablePacket.payload, retainablePacket.header.SequenceNumber)
+
+ // Rewrite the SSRC.
+ retainablePacket.header.SSRC = rtxSsrc
+ // Rewrite the payload type.
+ retainablePacket.header.PayloadType = rtxPayloadType
+ // Rewrite the sequence number.
+ retainablePacket.header.SequenceNumber = m.rtxSequencer.NextSequenceNumber()
+ // Remove padding if present.
+ if retainablePacket.header.Padding {
+ // Older versions of pion/rtp didn't have the Header.PaddingSize field and as a workaround
+ // users had to add padding to the payload. We need to handle this case here.
+ if retainablePacket.header.PaddingSize == 0 && len(retainablePacket.payload) > 0 {
+ paddingLength := int(retainablePacket.payload[len(retainablePacket.payload)-1])
+ if paddingLength > len(retainablePacket.payload) {
+ return nil, errPaddingOverflow
+ }
+ retainablePacket.payload = (*retainablePacket.buffer)[:len(retainablePacket.payload)-paddingLength]
+ }
+
+ retainablePacket.header.Padding = false
+ retainablePacket.header.PaddingSize = 0
+ }
+ }
+
+ return retainablePacket, nil
+}
+
+func (m *PacketFactoryCopy) releasePacket(header *rtp.Header, payload *[]byte) {
+ m.headerPool.Put(header)
+ if payload != nil {
+ m.payloadPool.Put(payload)
+ }
+}
+
+// PacketFactoryNoOp is a PacketFactory implementation that doesn't copy packets.
+type PacketFactoryNoOp struct{}
+
+// NewPacket constructs a new RetainablePacket that can be added to the RTPBuffer.
+func (f *PacketFactoryNoOp) NewPacket(
+ header *rtp.Header, payload []byte, _ uint32, _ uint8,
+) (*RetainablePacket, error) {
+ return &RetainablePacket{
+ onRelease: f.releasePacket,
+ count: 1,
+ header: header,
+ payload: payload,
+ sequenceNumber: header.SequenceNumber,
+ }, nil
+}
+
+func (f *PacketFactoryNoOp) releasePacket(_ *rtp.Header, _ *[]byte) {
+ // no-op
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/retainable_packet.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/retainable_packet.go
new file mode 100644
index 000000000..82ade097c
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/retainable_packet.go
@@ -0,0 +1,62 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package rtpbuffer
+
+import (
+ "sync"
+
+ "github.com/pion/rtp"
+)
+
+// RetainablePacket is a referenced counted RTP packet.
+type RetainablePacket struct {
+ onRelease func(*rtp.Header, *[]byte)
+
+ countMu sync.Mutex
+ count int
+
+ header *rtp.Header
+ buffer *[]byte
+ payload []byte
+
+ sequenceNumber uint16
+}
+
+// Header returns the RTP Header of the RetainablePacket.
+func (p *RetainablePacket) Header() *rtp.Header {
+ return p.header
+}
+
+// Payload returns the RTP Payload of the RetainablePacket.
+func (p *RetainablePacket) Payload() []byte {
+ return p.payload
+}
+
+// Retain increases the reference count of the RetainablePacket.
+func (p *RetainablePacket) Retain() error {
+ p.countMu.Lock()
+ defer p.countMu.Unlock()
+ if p.count == 0 {
+ // already released
+ return errPacketReleased
+ }
+ p.count++
+
+ return nil
+}
+
+// Release decreases the reference count of the RetainablePacket and frees if needed.
+func (p *RetainablePacket) Release() {
+ p.countMu.Lock()
+ defer p.countMu.Unlock()
+ p.count--
+
+ if p.count == 0 {
+ // release back to pool
+ p.onRelease(p.header, p.buffer)
+ p.header = nil
+ p.buffer = nil
+ p.payload = nil
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/rtpbuffer.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/rtpbuffer.go
new file mode 100644
index 000000000..94c7adfe1
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/rtpbuffer/rtpbuffer.go
@@ -0,0 +1,107 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package rtpbuffer provides a buffer for storing RTP packets
+package rtpbuffer
+
+import (
+ "fmt"
+)
+
+const (
+ // Uint16SizeHalf is half of a math.Uint16.
+ Uint16SizeHalf = 1 << 15
+
+ maxPayloadLen = 1460
+)
+
+// RTPBuffer stores RTP packets and allows custom logic
+// around the lifetime of them via the PacketFactory.
+type RTPBuffer struct {
+ packets []*RetainablePacket
+ size uint16
+ highestAdded uint16
+ started bool
+}
+
+// NewRTPBuffer constructs a new RTPBuffer.
+func NewRTPBuffer(size uint16) (*RTPBuffer, error) {
+ allowedSizes := make([]uint16, 0)
+ correctSize := false
+ for i := 0; i < 16; i++ {
+ if size == 1<= Uint16SizeHalf {
+ return nil
+ }
+
+ if diff >= r.size {
+ return nil
+ }
+
+ pkt := r.packets[seq%r.size]
+ if pkt != nil {
+ if pkt.sequenceNumber != seq {
+ return nil
+ }
+ // already released
+ if err := pkt.Retain(); err != nil {
+ return nil
+ }
+ }
+
+ return pkt
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/sequencenumber/unwrapper.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/sequencenumber/unwrapper.go
index 311ff09df..48500b3cc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/sequencenumber/unwrapper.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/internal/sequencenumber/unwrapper.go
@@ -9,7 +9,7 @@ const (
breakpoint = 32768 // half of max uint16
)
-// Unwrapper stores an unwrapped sequence number
+// Unwrapper stores an unwrapped sequence number.
type Unwrapper struct {
init bool
lastUnwrapped int64
@@ -19,18 +19,20 @@ func isNewer(value, previous uint16) bool {
if value-previous == breakpoint {
return value > previous
}
+
return value != previous && (value-previous) < breakpoint
}
-// Unwrap unwraps the next sequencenumber
+// Unwrap unwraps the next sequencenumber.
func (u *Unwrapper) Unwrap(i uint16) int64 {
if !u.init {
u.init = true
u.lastUnwrapped = int64(i)
+
return u.lastUnwrapped
}
- lastWrapped := uint16(u.lastUnwrapped)
+ lastWrapped := uint16(u.lastUnwrapped) //nolint:gosec // G115
delta := int64(i - lastWrapped)
if isNewer(i, lastWrapped) {
if delta < 0 {
@@ -41,5 +43,6 @@ func (u *Unwrapper) Unwrap(i uint16) int64 {
}
u.lastUnwrapped += delta
+
return u.lastUnwrapped
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
index b0fc2a69a..964a330e8 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/noop.go
@@ -28,7 +28,8 @@ func (i *NoOp) BindLocalStream(_ *StreamInfo, writer RTPWriter) RTPWriter {
// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
func (i *NoOp) UnbindLocalStream(_ *StreamInfo) {}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
+// BindRemoteStream lets you modify any incoming RTP packets.
+// It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
func (i *NoOp) BindRemoteStream(_ *StreamInfo, reader RTPReader) RTPReader {
return reader
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/encoder_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/encoder_interceptor.go
new file mode 100644
index 000000000..ee627e40a
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/encoder_interceptor.go
@@ -0,0 +1,128 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package flexfec
+
+import (
+ "errors"
+ "sync"
+
+ "github.com/pion/interceptor"
+ "github.com/pion/rtp"
+)
+
+// streamState holds the state for a single stream.
+type streamState struct {
+ mu sync.Mutex
+ flexFecEncoder FlexEncoder
+ packetBuffer []rtp.Packet
+}
+
+// FecInterceptor implements FlexFec.
+type FecInterceptor struct {
+ interceptor.NoOp
+ mu sync.Mutex
+ streams map[uint32]*streamState
+ numMediaPackets uint32
+ numFecPackets uint32
+ encoderFactory EncoderFactory
+}
+
+// FecInterceptorFactory creates new FecInterceptors.
+type FecInterceptorFactory struct {
+ opts []FecOption
+}
+
+// NewFecInterceptor returns a new Fec interceptor factory.
+func NewFecInterceptor(opts ...FecOption) (*FecInterceptorFactory, error) {
+ return &FecInterceptorFactory{opts: opts}, nil
+}
+
+// NewInterceptor constructs a new FecInterceptor.
+func (r *FecInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
+ interceptor := &FecInterceptor{
+ streams: make(map[uint32]*streamState),
+ numMediaPackets: 5,
+ numFecPackets: 2,
+ encoderFactory: FlexEncoder03Factory{},
+ }
+
+ for _, opt := range r.opts {
+ if err := opt(interceptor); err != nil {
+ return nil, err
+ }
+ }
+
+ return interceptor, nil
+}
+
+// UnbindLocalStream removes the stream state for a specific SSRC.
+func (r *FecInterceptor) UnbindLocalStream(info *interceptor.StreamInfo) {
+ r.mu.Lock()
+ defer r.mu.Unlock()
+
+ delete(r.streams, info.SSRC)
+}
+
+// BindLocalStream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method
+// will be called once per rtp packet.
+func (r *FecInterceptor) BindLocalStream(
+ info *interceptor.StreamInfo, writer interceptor.RTPWriter,
+) interceptor.RTPWriter {
+ if info.PayloadTypeForwardErrorCorrection == 0 || info.SSRCForwardErrorCorrection == 0 {
+ return writer
+ }
+
+ mediaSSRC := info.SSRC
+
+ r.mu.Lock()
+ stream := &streamState{
+ // Chromium supports version flexfec-03 of existing draft, this is the one we will configure by default
+ // although we should support configuring the latest (flexfec-20) as well.
+ flexFecEncoder: r.encoderFactory.NewEncoder(info.PayloadTypeForwardErrorCorrection, info.SSRCForwardErrorCorrection),
+ packetBuffer: make([]rtp.Packet, 0),
+ }
+ r.streams[mediaSSRC] = stream
+ r.mu.Unlock()
+
+ return interceptor.RTPWriterFunc(
+ func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
+ // Ignore non-media packets
+ if header.SSRC != mediaSSRC {
+ return writer.Write(header, payload, attributes)
+ }
+
+ var fecPackets []rtp.Packet
+ stream.mu.Lock()
+ stream.packetBuffer = append(stream.packetBuffer, rtp.Packet{
+ Header: *header,
+ Payload: payload,
+ })
+
+ // Check if we have enough packets to generate FEC
+ if len(stream.packetBuffer) == int(r.numMediaPackets) {
+ fecPackets = stream.flexFecEncoder.EncodeFec(stream.packetBuffer, r.numFecPackets)
+ // Reset the packet buffer now that we've sent the corresponding FEC packets.
+ stream.packetBuffer = nil
+ }
+ stream.mu.Unlock()
+
+ var errs []error
+ result, err := writer.Write(header, payload, attributes)
+ if err != nil {
+ errs = append(errs, err)
+ }
+
+ for _, packet := range fecPackets {
+ header := packet.Header
+
+ _, err = writer.Write(&header, packet.Payload, attributes)
+ if err != nil {
+ errs = append(errs, err)
+ }
+ }
+
+ return result, errors.Join(errs...)
+ },
+ )
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_coverage.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_coverage.go
new file mode 100644
index 000000000..1ffeefb5d
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_coverage.go
@@ -0,0 +1,177 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package flexfec
+
+import (
+ "github.com/pion/interceptor/pkg/flexfec/util"
+ "github.com/pion/rtp"
+)
+
+// Maximum number of media packets that can be protected by a single FEC packet.
+// We are not supporting the possibility of having an FEC packet protect multiple
+// SSRC source packets for now.
+// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
+const (
+ MaxMediaPackets uint32 = 110
+ MaxFecPackets uint32 = MaxMediaPackets
+)
+
+// ProtectionCoverage defines the map of RTP packets that individual Fec packets protect.
+type ProtectionCoverage struct {
+ // Array of masks, each mask capable of covering up to maxMediaPkts = 110.
+ // A mask is represented as a grouping of bytes where each individual bit
+ // represents the coverage for the media packet at the corresponding index.
+ packetMasks [MaxFecPackets]util.BitArray
+ numFecPackets uint32
+ numMediaPackets uint32
+ mediaPackets []rtp.Packet
+}
+
+// NewCoverage returns a new ProtectionCoverage object. numFecPackets represents the number of
+// Fec packets that we will be generating to cover the list of mediaPackets. This allows us to know
+// how big the underlying map should be.
+func NewCoverage(mediaPackets []rtp.Packet, numFecPackets uint32) *ProtectionCoverage {
+ numMediaPackets := uint32(len(mediaPackets)) //nolint:gosec // G115
+
+ // Basic sanity checks
+ if numMediaPackets <= 0 || numMediaPackets > MaxMediaPackets {
+ return nil
+ }
+
+ // We allocate the biggest array of bitmasks that respects the max constraints.
+ var packetMasks [MaxFecPackets]util.BitArray
+ for i := 0; i < int(MaxFecPackets); i++ {
+ packetMasks[i] = util.BitArray{}
+ }
+
+ coverage := &ProtectionCoverage{
+ packetMasks: packetMasks,
+ numFecPackets: 0,
+ numMediaPackets: 0,
+ mediaPackets: nil,
+ }
+
+ coverage.UpdateCoverage(mediaPackets, numFecPackets)
+
+ return coverage
+}
+
+// UpdateCoverage updates the ProtectionCoverage object with new bitmasks accounting for the numFecPackets
+// we want to use to protect the batch media packets.
+func (p *ProtectionCoverage) UpdateCoverage(mediaPackets []rtp.Packet, numFecPackets uint32) {
+ numMediaPackets := uint32(len(mediaPackets)) //nolint:gosec // G115
+
+ // Basic sanity checks
+ if numMediaPackets <= 0 || numMediaPackets > MaxMediaPackets {
+ return
+ }
+
+ p.mediaPackets = mediaPackets
+
+ if numFecPackets == p.numFecPackets && numMediaPackets == p.numMediaPackets {
+ // We have the same number of FEC packets covering the same number of media packets, we can simply
+ // reuse the previous coverage map with the updated media packets.
+ return
+ }
+
+ p.numFecPackets = numFecPackets
+ p.numMediaPackets = numMediaPackets
+
+ // The number of FEC packets and/or the number of packets has changed, we need to update the coverage map
+ // to reflect these new values.
+ p.resetCoverage()
+
+ // Generate FEC bit mask where numFecPackets FEC packets are covering numMediaPackets Media packets.
+ // In the packetMasks array, each FEC packet is represented by a single BitArray, each bit in a given BitArray
+ // corresponds to a specific Media packet.
+ // Ex: Row I, Col J is set to 1 -> FEC packet I will protect media packet J.
+ for fecPacketIndex := uint32(0); fecPacketIndex < numFecPackets; fecPacketIndex++ {
+ // We use an interleaved method to determine coverage. Given N FEC packets, Media packet X will be
+ // covered by FEC packet X % N.
+ coveredMediaPacketIndex := fecPacketIndex
+ for coveredMediaPacketIndex < numMediaPackets {
+ p.packetMasks[fecPacketIndex].SetBit(coveredMediaPacketIndex)
+ coveredMediaPacketIndex += numFecPackets
+ }
+ }
+}
+
+// ResetCoverage clears the underlying map so that we can reuse it for new batches of RTP packets.
+func (p *ProtectionCoverage) resetCoverage() {
+ for i := uint32(0); i < MaxFecPackets; i++ {
+ p.packetMasks[i].Reset()
+ }
+}
+
+// GetCoveredBy returns an iterator over RTP packets that are protected by the specified Fec packet index.
+func (p *ProtectionCoverage) GetCoveredBy(fecPacketIndex uint32) *util.MediaPacketIterator {
+ coverage := make([]uint32, 0, p.numMediaPackets)
+ for mediaPacketIndex := uint32(0); mediaPacketIndex < p.numMediaPackets; mediaPacketIndex++ {
+ if p.packetMasks[fecPacketIndex].GetBit(mediaPacketIndex) == 1 {
+ coverage = append(coverage, mediaPacketIndex)
+ }
+ }
+
+ return util.NewMediaPacketIterator(p.mediaPackets, coverage)
+}
+
+// ExtractMask1 returns the first section of the bitmask as defined by the FEC header.
+// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
+func (p *ProtectionCoverage) ExtractMask1(fecPacketIndex uint32) uint16 {
+ return extractMask1(p.packetMasks[fecPacketIndex])
+}
+
+// ExtractMask2 returns the second section of the bitmask as defined by the FEC header.
+// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
+func (p *ProtectionCoverage) ExtractMask2(fecPacketIndex uint32) uint32 {
+ return extractMask2(p.packetMasks[fecPacketIndex])
+}
+
+// ExtractMask3 returns the third section of the bitmask as defined by the FEC header.
+// https://datatracker.ietf.org/doc/html/rfc8627#section-4.2.2.1
+func (p *ProtectionCoverage) ExtractMask3(fecPacketIndex uint32) uint64 {
+ return extractMask3(p.packetMasks[fecPacketIndex])
+}
+
+// ExtractMask3_03 returns the third section of the bitmask as defined by the FEC header.
+// https://datatracker.ietf.org/doc/html/draft-ietf-payload-flexible-fec-scheme-03#section-4.2
+func (p *ProtectionCoverage) ExtractMask3_03(fecPacketIndex uint32) uint64 {
+ return extractMask3_03(p.packetMasks[fecPacketIndex])
+}
+
+func extractMask1(mask util.BitArray) uint16 {
+ // We get the first 16 bits (64 - 16 -> shift by 48) and we shift once more for K field
+ mask1 := mask.Lo >> 49
+
+ return uint16(mask1) //nolint:gosec // G115
+}
+
+func extractMask2(mask util.BitArray) uint32 {
+ // We remove the first 15 bits
+ mask2 := mask.Lo << 15
+ // We get the first 31 bits (64 - 32 -> shift by 32) and we shift once more for K field
+ mask2 >>= 33
+
+ return uint32(mask2) //nolint:gosec
+}
+
+func extractMask3(mask util.BitArray) uint64 {
+ // We remove the first 46 bits
+ maskLo := mask.Lo << 46
+ maskHi := mask.Hi >> 18
+ mask3 := maskLo | maskHi
+
+ return mask3
+}
+
+func extractMask3_03(mask util.BitArray) uint64 {
+ // We remove the first 46 bits
+ maskLo := mask.Lo << 46
+ maskHi := mask.Hi >> 18
+ mask3 := maskLo | maskHi
+ // We shift once for the K bit.
+ mask3 >>= 1
+
+ return mask3
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_decoder_03.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_decoder_03.go
new file mode 100644
index 000000000..56ccff0b9
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_decoder_03.go
@@ -0,0 +1,445 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package flexfec implements FlexFEC-03 to recover missing RTP packets due to packet loss.
+// https://datatracker.ietf.org/doc/html/draft-ietf-payload-flexible-fec-scheme-03
+package flexfec
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "sort"
+
+ "github.com/pion/logging"
+ "github.com/pion/rtp"
+)
+
+// Static errors for the flexfec package.
+var (
+ errPacketTruncated = errors.New("packet truncated")
+ errRetransmissionBitSet = errors.New("packet with retransmission bit set not supported")
+ errInflexibleGeneratorMatrix = errors.New("packet with inflexible generator matrix not supported")
+ errMultipleSSRCProtection = errors.New("multiple ssrc protection not supported")
+ errLastOptionalMaskKBitSetToFalse = errors.New("k-bit of last optional mask is set to false")
+)
+
+// fecDecoder is a WIP implementation decoder used for testing purposes.
+type fecDecoder struct {
+ logger logging.LeveledLogger
+ ssrc uint32
+ protectedStreamSSRC uint32
+ maxMediaPackets int
+ maxFECPackets int
+ recoveredPackets []rtp.Packet
+ receivedFECPackets []fecPacketState
+}
+
+func newFECDecoder(ssrc uint32, protectedStreamSSRC uint32) *fecDecoder {
+ return &fecDecoder{
+ logger: logging.NewDefaultLoggerFactory().NewLogger("fec_decoder"),
+ ssrc: ssrc,
+ protectedStreamSSRC: protectedStreamSSRC,
+ maxMediaPackets: 100,
+ maxFECPackets: 100,
+ recoveredPackets: make([]rtp.Packet, 0),
+ receivedFECPackets: make([]fecPacketState, 0),
+ }
+}
+
+func (d *fecDecoder) DecodeFec(receivedPacket rtp.Packet) []rtp.Packet {
+ if len(d.recoveredPackets) == d.maxMediaPackets {
+ backRecoveredPacket := d.recoveredPackets[len(d.recoveredPackets)-1]
+ if backRecoveredPacket.SSRC == receivedPacket.SSRC {
+ seqDiffVal := seqDiff(receivedPacket.SequenceNumber, backRecoveredPacket.SequenceNumber)
+ if seqDiffVal > uint16(d.maxMediaPackets) { //nolint:gosec
+ d.logger.Info("big gap in media sequence numbers - resetting buffers")
+ d.recoveredPackets = nil
+ d.receivedFECPackets = nil
+ }
+ }
+ }
+
+ d.insertPacket(receivedPacket)
+
+ return d.attemptRecovery()
+}
+
+func (d *fecDecoder) insertPacket(receivedPkt rtp.Packet) {
+ // Discard old FEC packets such that the sequence numbers in
+ // `received_fec_packets_` span at most 1/2 of the sequence number space.
+ // This is important for keeping `received_fec_packets_` sorted, and may
+ // also reduce the possibility of incorrect decoding due to sequence number
+ // wrap-around.
+ if len(d.receivedFECPackets) > 0 && receivedPkt.SSRC == d.ssrc {
+ toRemove := 0
+ for _, fecPkt := range d.receivedFECPackets {
+ if abs(int(receivedPkt.SequenceNumber)-int(fecPkt.packet.SequenceNumber)) > 0x3fff {
+ toRemove++
+ } else {
+ // No need to keep iterating, since |received_fec_packets_| is sorted.
+ break
+ }
+ }
+ }
+
+ switch receivedPkt.SSRC {
+ case d.ssrc:
+ d.insertFECPacket(receivedPkt)
+ case d.protectedStreamSSRC:
+ d.insertMediaPacket(receivedPkt)
+ }
+
+ d.discardOldRecoveredPackets()
+}
+
+func (d *fecDecoder) insertMediaPacket(receivedPkt rtp.Packet) {
+ for _, recoveredPacket := range d.recoveredPackets {
+ if recoveredPacket.SequenceNumber == receivedPkt.SequenceNumber {
+ return
+ }
+ }
+
+ d.recoveredPackets = append(d.recoveredPackets, receivedPkt)
+ sort.Slice(d.recoveredPackets, func(i, j int) bool {
+ return isNewerSeq(d.recoveredPackets[i].SequenceNumber, d.recoveredPackets[j].SequenceNumber)
+ })
+ d.updateCoveringFecPackets(receivedPkt)
+}
+
+func (d *fecDecoder) updateCoveringFecPackets(receivedPkt rtp.Packet) {
+ for _, fecPkt := range d.receivedFECPackets {
+ for _, protectedPacket := range fecPkt.protectedPackets {
+ if protectedPacket.seq == receivedPkt.SequenceNumber {
+ protectedPacket.packet = &receivedPkt
+ }
+ }
+ }
+}
+
+func (d *fecDecoder) insertFECPacket(fecPkt rtp.Packet) { //nolint:cyclop
+ for _, existingFECPacket := range d.receivedFECPackets {
+ if existingFECPacket.packet.SequenceNumber == fecPkt.SequenceNumber {
+ return
+ }
+ }
+
+ fec, err := parseFlexFEC03Header(fecPkt.Payload)
+ if err != nil {
+ d.logger.Errorf("failed to parse flexfec03 header: %v", err)
+
+ return
+ }
+
+ if fec.protectedSSRC != d.protectedStreamSSRC {
+ d.logger.Errorf("fec is protecting unknown ssrc, expected %d, got %d", fec.protectedSSRC, d.protectedStreamSSRC)
+
+ return
+ }
+
+ protectedSeqs := decodeMask(uint64(fec.mask0), 15, fec.seqNumBase)
+ if fec.mask1 != 0 {
+ protectedSeqs = append(protectedSeqs, decodeMask(uint64(fec.mask1), 31, fec.seqNumBase+15)...)
+ }
+ if fec.mask2 != 0 {
+ protectedSeqs = append(protectedSeqs, decodeMask(fec.mask2, 63, fec.seqNumBase+46)...)
+ }
+
+ if len(protectedSeqs) == 0 {
+ d.logger.Warn("empty fec packet mask")
+
+ return
+ }
+
+ protectedPackets := make([]*protectedPacket, 0, len(protectedSeqs))
+ protectedSeqIt := 0
+ recoveredPacketIt := 0
+
+ for protectedSeqIt < len(protectedSeqs) && recoveredPacketIt < len(d.recoveredPackets) {
+ switch {
+ case isNewerSeq(protectedSeqs[protectedSeqIt], d.recoveredPackets[recoveredPacketIt].SequenceNumber):
+ protectedPackets = append(protectedPackets, &protectedPacket{
+ seq: protectedSeqs[protectedSeqIt],
+ packet: nil,
+ })
+ protectedSeqIt++
+ case isNewerSeq(d.recoveredPackets[recoveredPacketIt].SequenceNumber, protectedSeqs[protectedSeqIt]):
+ recoveredPacketIt++
+ default:
+ protectedPackets = append(protectedPackets, &protectedPacket{
+ seq: protectedSeqs[protectedSeqIt],
+ packet: &d.recoveredPackets[recoveredPacketIt],
+ })
+ protectedSeqIt++
+ recoveredPacketIt++
+ }
+ }
+
+ for protectedSeqIt < len(protectedSeqs) {
+ protectedPackets = append(protectedPackets, &protectedPacket{
+ seq: protectedSeqs[protectedSeqIt],
+ packet: nil,
+ })
+ protectedSeqIt++
+ }
+ d.receivedFECPackets = append(d.receivedFECPackets, fecPacketState{
+ packet: fecPkt,
+ flexFec: fec,
+ protectedPackets: protectedPackets,
+ })
+
+ sort.Slice(d.receivedFECPackets, func(i, j int) bool {
+ return isNewerSeq(d.receivedFECPackets[i].packet.SequenceNumber, d.receivedFECPackets[j].packet.SequenceNumber)
+ })
+
+ if len(d.receivedFECPackets) > d.maxFECPackets {
+ d.receivedFECPackets = d.receivedFECPackets[1:]
+ }
+}
+
+func (d *fecDecoder) attemptRecovery() []rtp.Packet {
+ recoveredPackets := make([]rtp.Packet, 0)
+ for {
+ packetsRecovered := 0
+ for _, fecPkt := range d.receivedFECPackets {
+ packetsMissing := 0
+ for _, pkt := range fecPkt.protectedPackets {
+ if pkt.packet == nil {
+ packetsMissing++
+ if packetsMissing > 1 {
+ break
+ }
+ }
+ }
+
+ if packetsMissing != 1 {
+ continue
+ }
+
+ recovered, err := d.recoverPacket(&fecPkt) //nolint:gosec
+ if err != nil {
+ d.logger.Errorf("failed to recover packet: %v", err)
+ }
+
+ recoveredPackets = append(recoveredPackets, recovered)
+ d.recoveredPackets = append(d.recoveredPackets, recovered)
+ sort.Slice(d.recoveredPackets, func(i, j int) bool {
+ return isNewerSeq(d.recoveredPackets[i].SequenceNumber, d.recoveredPackets[j].SequenceNumber)
+ })
+
+ d.updateCoveringFecPackets(recovered)
+ d.discardOldRecoveredPackets()
+ packetsRecovered++
+ }
+
+ if packetsRecovered == 0 {
+ break
+ }
+ }
+
+ return recoveredPackets
+}
+
+func (d *fecDecoder) recoverPacket(fec *fecPacketState) (rtp.Packet, error) {
+ // https://datatracker.ietf.org/doc/html/draft-ietf-payload-flexible-fec-scheme-03#section-6.3.2
+
+ // 2. For the repair packet in T, extract the FEC bit string as the
+ // first 80 bits of the FEC header.
+ headerRecovery := make([]byte, 12)
+ copy(headerRecovery, fec.packet.Payload[:10])
+
+ var seqnum uint16
+ for _, protectedPacket := range fec.protectedPackets {
+ if protectedPacket.packet != nil {
+ // 1. For each of the source packets that are successfully received in
+ // T, compute the 80-bit string by concatenating the first 64 bits
+ // of their RTP header and the unsigned network-ordered 16-bit
+ // representation of their length in bytes minus 12.
+ receivedHeader, err := protectedPacket.packet.Header.Marshal()
+ if err != nil {
+ return rtp.Packet{}, fmt.Errorf("marshal received header: %w", err)
+ }
+ binary.BigEndian.PutUint16(receivedHeader[2:4], uint16(protectedPacket.packet.MarshalSize()-12)) //nolint:gosec
+ for i := 0; i < 8; i++ {
+ headerRecovery[i] ^= receivedHeader[i]
+ }
+ } else {
+ seqnum = protectedPacket.seq
+ }
+ }
+
+ // set version to 2
+ headerRecovery[0] |= 0x80
+ headerRecovery[0] &= 0xbf
+ payloadLength := binary.BigEndian.Uint16(headerRecovery[2:4])
+ binary.BigEndian.PutUint16(headerRecovery[2:4], seqnum)
+ binary.BigEndian.PutUint32(headerRecovery[8:12], d.protectedStreamSSRC)
+
+ payloadRecovery := make([]byte, payloadLength)
+ copy(payloadRecovery, fec.flexFec.payload)
+ for _, protectedPacket := range fec.protectedPackets {
+ if protectedPacket.packet != nil {
+ packet, err := protectedPacket.packet.Marshal()
+ if err != nil {
+ return rtp.Packet{}, fmt.Errorf("marshal protected packet: %w", err)
+ }
+ for i := 0; i < minInt(int(payloadLength), len(packet)-12); i++ {
+ payloadRecovery[i] ^= packet[12+i]
+ }
+ }
+ }
+
+ headerRecovery = append(headerRecovery, payloadRecovery...) //nolint:makezero
+
+ var packet rtp.Packet
+ err := packet.Unmarshal(headerRecovery)
+ if err != nil {
+ return rtp.Packet{}, fmt.Errorf("unmarshal recovered: %w", err)
+ }
+
+ return packet, nil
+}
+
+func (d *fecDecoder) discardOldRecoveredPackets() {
+ const limit = 192
+ if len(d.recoveredPackets) > limit {
+ d.recoveredPackets = d.recoveredPackets[len(d.recoveredPackets)-192:]
+ }
+}
+
+func decodeMask(mask uint64, bitCount uint16, seqNumBase uint16) []uint16 {
+ res := make([]uint16, 0)
+ for i := uint16(0); i < bitCount; i++ {
+ if (mask>>(bitCount-1-i))&1 == 1 {
+ res = append(res, seqNumBase+i)
+ }
+ }
+
+ return res
+}
+
+type fecPacketState struct {
+ packet rtp.Packet
+ flexFec flexFec
+ protectedPackets []*protectedPacket
+}
+
+type flexFec struct {
+ protectedSSRC uint32
+ seqNumBase uint16
+ mask0 uint16
+ mask1 uint32
+ mask2 uint64
+ payload []byte
+}
+
+type protectedPacket struct {
+ seq uint16
+ packet *rtp.Packet
+}
+
+func parseFlexFEC03Header(data []byte) (flexFec, error) {
+ if len(data) < 20 {
+ return flexFec{}, fmt.Errorf("%w: length %d", errPacketTruncated, len(data))
+ }
+
+ rBit := (data[0] & 0x80) != 0
+ if rBit {
+ return flexFec{}, errRetransmissionBitSet
+ }
+
+ fBit := (data[0] & 0x40) != 0
+ if fBit {
+ return flexFec{}, errInflexibleGeneratorMatrix
+ }
+
+ ssrcCount := data[8]
+ if ssrcCount != 1 {
+ return flexFec{}, fmt.Errorf("%w: count %d", errMultipleSSRCProtection, ssrcCount)
+ }
+
+ protectedSSRC := binary.BigEndian.Uint32(data[12:])
+ seqNumBase := binary.BigEndian.Uint16(data[16:])
+ rawPacketMask := data[18:]
+ var payload []byte
+
+ kBit0 := (rawPacketMask[0] & 0x80) != 0
+ maskPart0 := binary.BigEndian.Uint16(rawPacketMask[0:2]) & 0x7FFF
+ var maskPart1 uint32
+ var maskPart2 uint64
+
+ if kBit0 { //nolint:nestif
+ payload = rawPacketMask[2:]
+ } else {
+ if len(data) < 24 {
+ return flexFec{}, fmt.Errorf("%w: length %d", errPacketTruncated, len(data))
+ }
+
+ kBit1 := (rawPacketMask[2] & 0x80) != 0
+ maskPart1 = binary.BigEndian.Uint32(rawPacketMask[2:]) & 0x7FFFFFFF
+
+ if kBit1 {
+ payload = rawPacketMask[6:]
+ } else {
+ if len(data) < 32 {
+ return flexFec{}, fmt.Errorf("%w: length %d", errPacketTruncated, len(data))
+ }
+
+ kBit2 := (rawPacketMask[6] & 0x80) != 0
+ maskPart2 = binary.BigEndian.Uint64(rawPacketMask[6:]) & 0x7FFFFFFFFFFFFFFF
+
+ if kBit2 {
+ payload = rawPacketMask[14:]
+ } else {
+ return flexFec{}, errLastOptionalMaskKBitSetToFalse
+ }
+ }
+ }
+
+ return flexFec{
+ protectedSSRC: protectedSSRC,
+ seqNumBase: seqNumBase,
+ mask0: maskPart0,
+ mask1: maskPart1,
+ mask2: maskPart2,
+ payload: payload,
+ }, nil
+}
+
+func seqDiff(a, b uint16) uint16 {
+ return minUInt16(a-b, b-a)
+}
+
+func minInt(a, b int) int {
+ if a < b {
+ return a
+ }
+
+ return b
+}
+
+func minUInt16(a, b uint16) uint16 {
+ if a < b {
+ return a
+ }
+
+ return b
+}
+
+func abs(x int) int {
+ if x >= 0 {
+ return x
+ }
+
+ return -x
+}
+
+func isNewerSeq(prevValue, value uint16) bool {
+ // half-way mark
+ breakpoint := uint16(0x8000)
+ if value-prevValue == breakpoint {
+ return value > prevValue
+ }
+
+ return value != prevValue && (value-prevValue) < breakpoint
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder.go
new file mode 100644
index 000000000..3e09551f5
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder.go
@@ -0,0 +1,209 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package flexfec implements FlexFEC to recover missing RTP packets due to packet loss.
+// https://datatracker.ietf.org/doc/html/rfc8627
+package flexfec
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/interceptor/pkg/flexfec/util"
+ "github.com/pion/rtp"
+)
+
+const (
+ // BaseRTPHeaderSize represents the minium RTP packet header size in bytes.
+ BaseRTPHeaderSize = 12
+ // BaseFecHeaderSize represents the minium FEC payload's header size including the
+ // required first mask.
+ BaseFecHeaderSize = 12
+)
+
+// EncoderFactory is an interface for generic FEC encoders.
+type EncoderFactory interface {
+ NewEncoder(payloadType uint8, ssrc uint32) FlexEncoder
+}
+
+// FlexEncoder is the interface that FecInterceptor uses to encode Fec packets.
+type FlexEncoder interface {
+ EncodeFec(mediaPackets []rtp.Packet, numFecPackets uint32) []rtp.Packet
+}
+
+// FlexEncoder20 implementation is WIP, contains bugs and no tests. Check out FlexEncoder03.
+type FlexEncoder20 struct {
+ fecBaseSn uint16
+ payloadType uint8
+ ssrc uint32
+ coverage *ProtectionCoverage
+}
+
+// NewFlexEncoder returns a new FlexEncoder20.
+// FlexEncoder20 implementation is WIP, contains bugs and no tests. Check out FlexEncoder03.
+func NewFlexEncoder(payloadType uint8, ssrc uint32) *FlexEncoder20 {
+ return &FlexEncoder20{
+ payloadType: payloadType,
+ ssrc: ssrc,
+ fecBaseSn: uint16(1000),
+ }
+}
+
+// EncodeFec returns a list of generated RTP packets with FEC payloads that protect the specified mediaPackets.
+// This method does not account for missing RTP packets in the mediaPackets array nor does it account for
+// them being passed out of order.
+func (flex *FlexEncoder20) EncodeFec(mediaPackets []rtp.Packet, numFecPackets uint32) []rtp.Packet {
+ // Start by defining which FEC packets cover which media packets
+ if flex.coverage == nil {
+ flex.coverage = NewCoverage(mediaPackets, numFecPackets)
+ } else {
+ flex.coverage.UpdateCoverage(mediaPackets, numFecPackets)
+ }
+
+ if flex.coverage == nil {
+ return nil
+ }
+
+ // Generate FEC payloads
+ fecPackets := make([]rtp.Packet, numFecPackets)
+ for fecPacketIndex := uint32(0); fecPacketIndex < numFecPackets; fecPacketIndex++ {
+ fecPackets[fecPacketIndex] = flex.encodeFlexFecPacket(fecPacketIndex, mediaPackets[0].SequenceNumber)
+ }
+
+ return fecPackets
+}
+
+func (flex *FlexEncoder20) encodeFlexFecPacket(fecPacketIndex uint32, mediaBaseSn uint16) rtp.Packet {
+ mediaPacketsIt := flex.coverage.GetCoveredBy(fecPacketIndex)
+ flexFecHeader := flex.encodeFlexFecHeader(
+ mediaPacketsIt,
+ flex.coverage.ExtractMask1(fecPacketIndex),
+ flex.coverage.ExtractMask2(fecPacketIndex),
+ flex.coverage.ExtractMask3(fecPacketIndex),
+ mediaBaseSn,
+ )
+ flexFecRepairPayload := flex.encodeFlexFecRepairPayload(mediaPacketsIt.Reset())
+
+ packet := rtp.Packet{
+ Header: rtp.Header{
+ Version: 2,
+ Padding: false,
+ Extension: false,
+ Marker: false,
+ PayloadType: flex.payloadType,
+ SequenceNumber: flex.fecBaseSn,
+ Timestamp: 54243243,
+ SSRC: flex.ssrc,
+ CSRC: []uint32{},
+ },
+ Payload: append(flexFecHeader, flexFecRepairPayload...),
+ }
+ flex.fecBaseSn++
+
+ return packet
+}
+
+func (flex *FlexEncoder20) encodeFlexFecHeader(
+ mediaPackets *util.MediaPacketIterator,
+ mask1 uint16,
+ optionalMask2 uint32,
+ optionalMask3 uint64,
+ mediaBaseSn uint16,
+) []byte {
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0|0|P|X| CC |M| PT recovery | length recovery |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TS recovery |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SN base_i |k| Mask [0-14] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |k| Mask [15-45] (optional) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Mask [46-109] (optional) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... next SN base and Mask for CSRC_i in CSRC list ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ : Repair "Payload" follows FEC Header :
+ : :
+ */
+
+ // Get header size - This depends on the size of the bitmask.
+ headerSize := BaseFecHeaderSize
+ if optionalMask2 > 0 {
+ headerSize += 4
+ }
+ if optionalMask3 > 0 {
+ headerSize += 8
+ }
+
+ // Allocate the FlexFec header
+ flexFecHeader := make([]byte, headerSize)
+
+ // XOR the relevant fields for the header
+ // TO DO - CHECK TO SEE IF THE MARSHALTO() call works with this.
+ tmpMediaPacketBuf := make([]byte, headerSize)
+ for mediaPackets.HasNext() {
+ mediaPacket := mediaPackets.Next()
+ n, err := mediaPacket.MarshalTo(tmpMediaPacketBuf)
+
+ if n == 0 || err != nil {
+ return nil
+ }
+
+ // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields
+ flexFecHeader[0] ^= tmpMediaPacketBuf[0]
+ flexFecHeader[1] ^= tmpMediaPacketBuf[1]
+
+ // XOR the length recovery field
+ lengthRecoveryVal := uint16(mediaPacket.MarshalSize() - BaseRTPHeaderSize) //nolint:gosec // G115
+ flexFecHeader[2] ^= uint8(lengthRecoveryVal >> 8) //nolint:gosec // G115
+ flexFecHeader[3] ^= uint8(lengthRecoveryVal) //nolint:gosec // G115
+
+ // XOR the 5th to 8th bytes of the header: the timestamp field
+ flexFecHeader[4] ^= flexFecHeader[4]
+ flexFecHeader[5] ^= flexFecHeader[5]
+ flexFecHeader[6] ^= flexFecHeader[6]
+ flexFecHeader[7] ^= flexFecHeader[7]
+ }
+
+ // Write the base SN for the batch of media packets
+ binary.BigEndian.PutUint16(flexFecHeader[8:10], mediaBaseSn)
+
+ // Write the bitmasks to the header
+ binary.BigEndian.PutUint16(flexFecHeader[10:12], mask1)
+
+ if optionalMask2 > 0 {
+ binary.BigEndian.PutUint32(flexFecHeader[12:16], optionalMask2)
+ flexFecHeader[10] |= 0b10000000
+ }
+ if optionalMask3 > 0 {
+ binary.BigEndian.PutUint64(flexFecHeader[16:24], optionalMask3)
+ flexFecHeader[12] |= 0b10000000
+ }
+
+ return flexFecHeader
+}
+
+func (flex *FlexEncoder20) encodeFlexFecRepairPayload(mediaPackets *util.MediaPacketIterator) []byte {
+ flexFecPayload := make([]byte, len(mediaPackets.First().Payload))
+
+ for mediaPackets.HasNext() {
+ mediaPacketPayload := mediaPackets.Next().Payload
+
+ if len(flexFecPayload) < len(mediaPacketPayload) {
+ // Expected FEC packet payload is bigger that what we can currently store,
+ // we need to resize.
+ flexFecPayloadTmp := make([]byte, len(mediaPacketPayload))
+ copy(flexFecPayloadTmp, flexFecPayload)
+ flexFecPayload = flexFecPayloadTmp
+ }
+ for byteIndex := 0; byteIndex < len(mediaPacketPayload); byteIndex++ {
+ flexFecPayload[byteIndex] ^= mediaPacketPayload[byteIndex]
+ }
+ }
+
+ return flexFecPayload
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder_03.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder_03.go
new file mode 100644
index 000000000..37b905dd3
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/flexfec_encoder_03.go
@@ -0,0 +1,255 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package flexfec implements FlexFEC to recover missing RTP packets due to packet loss.
+// https://datatracker.ietf.org/doc/html/rfc8627
+package flexfec
+
+import (
+ "encoding/binary"
+
+ "github.com/pion/interceptor/pkg/flexfec/util"
+ "github.com/pion/rtp"
+)
+
+const (
+ // BaseFec03HeaderSize represents the minium FEC payload's header size including the
+ // required first mask.
+ BaseFec03HeaderSize = 20
+)
+
+// FlexEncoder03 implements the Fec encoding mechanism for the "Flex" variant of FlexFec.
+type FlexEncoder03 struct {
+ fecBaseSn uint16
+ payloadType uint8
+ ssrc uint32
+ coverage *ProtectionCoverage
+}
+
+// FlexEncoder03Factory is a factory for FlexFEC-03 encoders.
+type FlexEncoder03Factory struct{}
+
+// NewEncoder creates new FlexFEC-03 encoder.
+func (f FlexEncoder03Factory) NewEncoder(payloadType uint8, ssrc uint32) FlexEncoder {
+ return NewFlexEncoder03(payloadType, ssrc)
+}
+
+// NewFlexEncoder03 creates new FlexFEC-03 encoder.
+func NewFlexEncoder03(payloadType uint8, ssrc uint32) *FlexEncoder03 {
+ return &FlexEncoder03{
+ payloadType: payloadType,
+ ssrc: ssrc,
+ fecBaseSn: uint16(1000),
+ }
+}
+
+// EncodeFec returns a list of generated RTP packets with FEC payloads that protect the specified mediaPackets.
+// This method returns nil in case of missing RTP packets in the mediaPackets array or packets passed out of order.
+func (flex *FlexEncoder03) EncodeFec(mediaPackets []rtp.Packet, numFecPackets uint32) []rtp.Packet {
+ // Check if mediaPackets is empty
+ if len(mediaPackets) == 0 {
+ return nil
+ }
+
+ // Check if RTP packets are in order by comparing sequence numbers
+ for i := 1; i < len(mediaPackets); i++ {
+ if mediaPackets[i].SequenceNumber != mediaPackets[i-1].SequenceNumber+1 {
+ // Packets are not in order or there are missing packets
+ return nil
+ }
+ }
+
+ // Start by defining which FEC packets cover which media packets
+ if flex.coverage == nil {
+ flex.coverage = NewCoverage(mediaPackets, numFecPackets)
+ } else {
+ flex.coverage.UpdateCoverage(mediaPackets, numFecPackets)
+ }
+
+ if flex.coverage == nil {
+ return nil
+ }
+
+ // Generate FEC payloads
+ fecPackets := make([]rtp.Packet, numFecPackets)
+ for fecPacketIndex := uint32(0); fecPacketIndex < numFecPackets; fecPacketIndex++ {
+ fecPackets[fecPacketIndex] = flex.encodeFlexFecPacket(fecPacketIndex, mediaPackets[0].SequenceNumber)
+ }
+
+ return fecPackets
+}
+
+func (flex *FlexEncoder03) encodeFlexFecPacket(fecPacketIndex uint32, mediaBaseSn uint16) rtp.Packet {
+ mediaPacketsIt := flex.coverage.GetCoveredBy(fecPacketIndex)
+ flexFecHeader := flex.encodeFlexFecHeader(
+ mediaPacketsIt,
+ flex.coverage.ExtractMask1(fecPacketIndex),
+ flex.coverage.ExtractMask2(fecPacketIndex),
+ flex.coverage.ExtractMask3_03(fecPacketIndex),
+ mediaBaseSn,
+ )
+ flexFecRepairPayload := flex.encodeFlexFecRepairPayload(mediaPacketsIt.Reset())
+
+ packet := rtp.Packet{
+ Header: rtp.Header{
+ Version: 2,
+ Padding: false,
+ Extension: false,
+ Marker: false,
+ PayloadType: flex.payloadType,
+ SequenceNumber: flex.fecBaseSn,
+ Timestamp: 54243243,
+ SSRC: flex.ssrc,
+ CSRC: []uint32{},
+ },
+ Payload: append(flexFecHeader, flexFecRepairPayload...),
+ }
+ flex.fecBaseSn++
+
+ return packet
+}
+
+func (flex *FlexEncoder03) encodeFlexFecHeader( //nolint:cyclop
+ mediaPackets *util.MediaPacketIterator,
+ mask1 uint16,
+ optionalMask2 uint32,
+ optionalMask3 uint64,
+ mediaBaseSn uint16,
+) []byte {
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |0|0| P|X| CC |M| PT recovery | length recovery |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | TS recovery |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRCCount | reserved |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC_i |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SN base_i |k| Mask [0-14] |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |k| Mask [15-45] (optional) |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |k| |
+ +-+ Mask [46-108] (optional) |
+ | |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... next in SSRC_i ... |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ // Get header size - This depends on the size of the bitmask.
+ headerSize := BaseFec03HeaderSize
+ if optionalMask2 > 0 || optionalMask3 > 0 {
+ headerSize += 4
+ }
+ if optionalMask3 > 0 {
+ headerSize += 8
+ }
+
+ // Allocate the FlexFec header
+ flexFecHeader := make([]byte, headerSize)
+
+ // We allocate a single temporary buffer to store the mediaPacket bytes. This reduces
+ // overall allocations.
+ tmpMediaPacketBuf := make([]byte, 0)
+ for mediaPackets.HasNext() {
+ mediaPacket := mediaPackets.Next()
+
+ if mediaPacket.MarshalSize() > len(tmpMediaPacketBuf) {
+ // The temporary buffer is too small, we need to resize.
+ tmpMediaPacketBuf = make([]byte, mediaPacket.MarshalSize())
+ }
+ n, err := mediaPacket.MarshalTo(tmpMediaPacketBuf)
+
+ if n == 0 || err != nil {
+ return nil
+ }
+
+ // XOR the first 2 bytes of the header: V, P, X, CC, M, PT fields
+ flexFecHeader[0] ^= tmpMediaPacketBuf[0]
+ flexFecHeader[1] ^= tmpMediaPacketBuf[1]
+
+ // Clear the first 2 bits
+ flexFecHeader[0] &= 0b00111111
+
+ // XOR the length recovery field
+ lengthRecoveryVal := uint16(mediaPacket.MarshalSize() - BaseRTPHeaderSize) //nolint:gosec // G115
+ flexFecHeader[2] ^= uint8(lengthRecoveryVal >> 8) //nolint:gosec // G115
+ flexFecHeader[3] ^= uint8(lengthRecoveryVal) //nolint:gosec // G115
+
+ // XOR the 5th to 8th bytes of the header: the timestamp field
+ flexFecHeader[4] ^= tmpMediaPacketBuf[4]
+ flexFecHeader[5] ^= tmpMediaPacketBuf[5]
+ flexFecHeader[6] ^= tmpMediaPacketBuf[6]
+ flexFecHeader[7] ^= tmpMediaPacketBuf[7]
+ }
+
+ // Write the SSRC count
+ flexFecHeader[8] = 1
+
+ // Write 0s in reserved
+ flexFecHeader[9] = 0
+ flexFecHeader[10] = 0
+ flexFecHeader[11] = 0
+
+ // Write the SSRC of media packets protected by this FEC packet
+ binary.BigEndian.PutUint32(flexFecHeader[12:16], mediaPackets.First().SSRC)
+
+ // Write the base SN for the batch of media packets
+ binary.BigEndian.PutUint16(flexFecHeader[16:18], mediaBaseSn)
+
+ // Write the bitmasks to the header
+ binary.BigEndian.PutUint16(flexFecHeader[18:20], mask1)
+
+ if optionalMask2 == 0 && optionalMask3 == 0 {
+ flexFecHeader[18] |= 0b10000000
+
+ return flexFecHeader
+ }
+ binary.BigEndian.PutUint32(flexFecHeader[20:24], optionalMask2)
+
+ if optionalMask3 == 0 {
+ flexFecHeader[20] |= 0b10000000
+ } else {
+ binary.BigEndian.PutUint64(flexFecHeader[24:32], optionalMask3)
+ flexFecHeader[24] |= 0b10000000
+ }
+
+ return flexFecHeader
+}
+
+func (flex *FlexEncoder03) encodeFlexFecRepairPayload(mediaPackets *util.MediaPacketIterator) []byte {
+ flexFecPayload := make([]byte, mediaPackets.First().MarshalSize()-BaseRTPHeaderSize)
+ tmpMediaPacketBuf := make([]byte, 0)
+
+ for mediaPackets.HasNext() {
+ mediaPacket := mediaPackets.Next()
+
+ if mediaPacket.MarshalSize() > len(tmpMediaPacketBuf) {
+ tmpMediaPacketBuf = make([]byte, mediaPacket.MarshalSize())
+ }
+
+ n, err := mediaPacket.MarshalTo(tmpMediaPacketBuf)
+
+ if n == 0 || err != nil {
+ return nil
+ }
+
+ if len(flexFecPayload) < mediaPacket.MarshalSize()-BaseRTPHeaderSize {
+ // Expected FEC packet payload is bigger that what we can currently store,
+ // we need to resize.
+ flexFecPayloadTmp := make([]byte, mediaPacket.MarshalSize()-BaseRTPHeaderSize)
+ copy(flexFecPayloadTmp, flexFecPayload)
+ flexFecPayload = flexFecPayloadTmp
+ }
+
+ for byteIndex := 0; byteIndex < mediaPacket.MarshalSize()-BaseRTPHeaderSize; byteIndex++ {
+ flexFecPayload[byteIndex] ^= tmpMediaPacketBuf[byteIndex+BaseRTPHeaderSize]
+ }
+ }
+
+ return flexFecPayload
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/option.go
new file mode 100644
index 000000000..70e61e0f9
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/option.go
@@ -0,0 +1,34 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package flexfec
+
+// FecOption can be used to set initial options on Fec encoder interceptors.
+type FecOption func(d *FecInterceptor) error
+
+// NumMediaPackets sets the number of media packets to accumulate before generating another FEC packets batch.
+func NumMediaPackets(numMediaPackets uint32) FecOption {
+ return func(f *FecInterceptor) error {
+ f.numMediaPackets = numMediaPackets
+
+ return nil
+ }
+}
+
+// NumFECPackets sets the number of FEC packets to generate for each batch of media packets.
+func NumFECPackets(numFecPackets uint32) FecOption {
+ return func(f *FecInterceptor) error {
+ f.numFecPackets = numFecPackets
+
+ return nil
+ }
+}
+
+// FECEncoderFactory sets the custom factory for constructing the FEC Encoders.
+func FECEncoderFactory(factory EncoderFactory) FecOption {
+ return func(f *FecInterceptor) error {
+ f.encoderFactory = factory
+
+ return nil
+ }
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/bitarray.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/bitarray.go
new file mode 100644
index 000000000..0840aabf7
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/bitarray.go
@@ -0,0 +1,47 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package util implements utilities to better support Fec decoding / encoding.
+package util
+
+// BitArray provides support for bitmask manipulations.
+type BitArray struct {
+ Lo uint64 // leftmost 64 bits
+ Hi uint64 // rightmost 64 bits
+}
+
+// SetBit sets a bit to the specified bit value on the bitmask.
+func (b *BitArray) SetBit(bitIndex uint32) {
+ if bitIndex < 64 {
+ b.Lo |= uint64(0b1) << (63 - bitIndex)
+ } else {
+ hiBitIndex := bitIndex - 64
+ b.Hi |= uint64(0b1) << (63 - hiBitIndex)
+ }
+}
+
+// Reset clears the bitmask.
+func (b *BitArray) Reset() {
+ b.Lo = 0
+ b.Hi = 0
+}
+
+// GetBit returns the bit value at a specified index of the bitmask.
+func (b *BitArray) GetBit(bitIndex uint32) uint8 {
+ if bitIndex < 64 {
+ result := (b.Lo & (uint64(0b1) << (63 - bitIndex)))
+ if result > 0 {
+ return 1
+ }
+
+ return 0
+ }
+
+ hiBitIndex := bitIndex - 64
+ result := (b.Hi & (uint64(0b1) << (63 - hiBitIndex)))
+ if result > 0 {
+ return 1
+ }
+
+ return 0
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/media_packet_iterator.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/media_packet_iterator.go
new file mode 100644
index 000000000..a9cc5fdc9
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/flexfec/util/media_packet_iterator.go
@@ -0,0 +1,56 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package util
+
+import "github.com/pion/rtp"
+
+// MediaPacketIterator supports iterating through a list of media packets protected by
+// a specific Fec packet.
+type MediaPacketIterator struct {
+ mediaPackets []rtp.Packet
+ coveredIndices []uint32
+ nextIndex int
+}
+
+// NewMediaPacketIterator returns a new MediaPacketIterator.
+func NewMediaPacketIterator(mediaPackets []rtp.Packet, coveredIndices []uint32) *MediaPacketIterator {
+ return &MediaPacketIterator{
+ mediaPackets: mediaPackets,
+ coveredIndices: coveredIndices,
+ nextIndex: 0,
+ }
+}
+
+// Reset sets the starting iterating index back to 0.
+func (m *MediaPacketIterator) Reset() *MediaPacketIterator {
+ m.nextIndex = 0
+
+ return m
+}
+
+// HasNext indicates whether or not there are more media packets
+// that can be iterated through.
+func (m *MediaPacketIterator) HasNext() bool {
+ return m.nextIndex < len(m.coveredIndices)
+}
+
+// Next returns the next media packet to iterate through.
+func (m *MediaPacketIterator) Next() *rtp.Packet {
+ if m.nextIndex == len(m.coveredIndices) {
+ return nil
+ }
+ packet := m.mediaPackets[m.coveredIndices[m.nextIndex]]
+ m.nextIndex++
+
+ return &packet
+}
+
+// First returns the first media packet to iterate through.
+func (m *MediaPacketIterator) First() *rtp.Packet {
+ if len(m.coveredIndices) == 0 {
+ return nil
+ }
+
+ return &m.mediaPackets[m.coveredIndices[0]]
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
index b47ec39c2..8b0958d01 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/errors.go
@@ -3,13 +3,7 @@
package nack
-import "errors"
+import "github.com/pion/interceptor/internal/rtpbuffer"
-// ErrInvalidSize is returned by newReceiveLog/newSendBuffer, when an incorrect buffer size is supplied.
-var ErrInvalidSize = errors.New("invalid buffer size")
-
-var (
- errPacketReleased = errors.New("could not retain packet, already released")
- errFailedToCastHeaderPool = errors.New("could not access header pool, failed cast")
- errFailedToCastPayloadPool = errors.New("could not access payload pool, failed cast")
-)
+// ErrInvalidSize is returned by newReceiveLog/newRTPBuffer, when an incorrect buffer size is supplied.
+var ErrInvalidSize = rtpbuffer.ErrInvalidSize
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
index ab2bb2c52..10c8a01b4 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_interceptor.go
@@ -13,14 +13,14 @@ import (
"github.com/pion/rtcp"
)
-// GeneratorInterceptorFactory is a interceptor.Factory for a GeneratorInterceptor
+// GeneratorInterceptorFactory is a interceptor.Factory for a GeneratorInterceptor.
type GeneratorInterceptorFactory struct {
opts []GeneratorOption
}
-// NewInterceptor constructs a new ReceiverInterceptor
+// NewInterceptor constructs a new ReceiverInterceptor.
func (g *GeneratorInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &GeneratorInterceptor{
+ generatorInterceptor := &GeneratorInterceptor{
streamsFilter: streamSupportNack,
size: 512,
skipLastN: 0,
@@ -33,16 +33,16 @@ func (g *GeneratorInterceptorFactory) NewInterceptor(_ string) (interceptor.Inte
}
for _, opt := range g.opts {
- if err := opt(i); err != nil {
+ if err := opt(generatorInterceptor); err != nil {
return nil, err
}
}
- if _, err := newReceiveLog(i.size); err != nil {
+ if _, err := newReceiveLog(generatorInterceptor.size); err != nil {
return nil, err
}
- return i, nil
+ return generatorInterceptor, nil
}
// GeneratorInterceptor interceptor generates nack feedback messages.
@@ -63,13 +63,13 @@ type GeneratorInterceptor struct {
receiveLogsMu sync.Mutex
}
-// NewGeneratorInterceptor returns a new GeneratorInterceptorFactory
+// NewGeneratorInterceptor returns a new GeneratorInterceptorFactory.
func NewGeneratorInterceptor(opts ...GeneratorOption) (*GeneratorInterceptorFactory, error) {
return &GeneratorInterceptorFactory{opts}, nil
}
-// BindRTCPWriter lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method
-// will be called once per packet batch.
+// BindRTCPWriter lets you modify any outgoing RTCP packets. It is called once per PeerConnection.
+// The returned method will be called once per packet batch.
func (n *GeneratorInterceptor) BindRTCPWriter(writer interceptor.RTCPWriter) interceptor.RTCPWriter {
n.m.Lock()
defer n.m.Unlock()
@@ -85,9 +85,11 @@ func (n *GeneratorInterceptor) BindRTCPWriter(writer interceptor.RTCPWriter) int
return writer
}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
-// will be called once per rtp packet.
-func (n *GeneratorInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
+// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream.
+// The returned method will be called once per rtp packet.
+func (n *GeneratorInterceptor) BindRemoteStream(
+ info *interceptor.StreamInfo, reader interceptor.RTPReader,
+) interceptor.RTPReader {
if !n.streamsFilter(info) {
return reader
}
@@ -124,7 +126,7 @@ func (n *GeneratorInterceptor) UnbindRemoteStream(info *interceptor.StreamInfo)
n.receiveLogsMu.Unlock()
}
-// Close closes the interceptor
+// Close closes the interceptor.
func (n *GeneratorInterceptor) Close() error {
defer n.wg.Wait()
n.m.Lock()
@@ -137,12 +139,15 @@ func (n *GeneratorInterceptor) Close() error {
return nil
}
-// nolint:gocognit
+// nolint:gocognit,cyclop
func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
defer n.wg.Done()
senderSSRC := rand.Uint32() // #nosec
+ missingPacketSeqNums := make([]uint16, n.size)
+ filteredMissingPacket := make([]uint16, n.size)
+
ticker := time.NewTicker(n.interval)
defer ticker.Stop()
for {
@@ -153,7 +158,7 @@ func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
defer n.receiveLogsMu.Unlock()
for ssrc, receiveLog := range n.receiveLogs {
- missing := receiveLog.missingSeqNumbers(n.skipLastN)
+ missing := receiveLog.missingSeqNumbers(n.skipLastN, missingPacketSeqNums)
if len(missing) == 0 || n.nackCountLogs[ssrc] == nil {
n.nackCountLogs[ssrc] = map[uint16]uint16{}
@@ -162,22 +167,33 @@ func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
continue
}
- filteredMissing := []uint16{}
+ nack := &rtcp.TransportLayerNack{} // nolint:ineffassign,wastedassign
+
+ c := 0 // nolint:varnamelen,
if n.maxNacksPerPacket > 0 {
for _, missingSeq := range missing {
if n.nackCountLogs[ssrc][missingSeq] < n.maxNacksPerPacket {
- filteredMissing = append(filteredMissing, missingSeq)
+ filteredMissingPacket[c] = missingSeq
+ c++
}
n.nackCountLogs[ssrc][missingSeq]++
}
- } else {
- filteredMissing = missing
- }
- nack := &rtcp.TransportLayerNack{
- SenderSSRC: senderSSRC,
- MediaSSRC: ssrc,
- Nacks: rtcp.NackPairsFromSequenceNumbers(filteredMissing),
+ if c == 0 {
+ continue
+ }
+
+ nack = &rtcp.TransportLayerNack{
+ SenderSSRC: senderSSRC,
+ MediaSSRC: ssrc,
+ Nacks: rtcp.NackPairsFromSequenceNumbers(filteredMissingPacket[:c]),
+ }
+ } else {
+ nack = &rtcp.TransportLayerNack{
+ SenderSSRC: senderSSRC,
+ MediaSSRC: ssrc,
+ Nacks: rtcp.NackPairsFromSequenceNumbers(missing),
+ }
}
for nackSeq := range n.nackCountLogs[ssrc] {
@@ -185,6 +201,7 @@ func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
for _, missingSeq := range missing {
if missingSeq == nackSeq {
isMissing = true
+
break
}
}
@@ -193,10 +210,6 @@ func (n *GeneratorInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
}
}
- if len(filteredMissing) == 0 {
- continue
- }
-
if _, err := rtcpWriter.Write([]rtcp.Packet{nack}, interceptor.Attributes{}); err != nil {
n.log.Warnf("failed sending nack: %+v", err)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
index 5403e3eee..db84093ae 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/generator_option.go
@@ -10,56 +10,63 @@ import (
"github.com/pion/logging"
)
-// GeneratorOption can be used to configure GeneratorInterceptor
+// GeneratorOption can be used to configure GeneratorInterceptor.
type GeneratorOption func(r *GeneratorInterceptor) error
// GeneratorSize sets the size of the interceptor.
-// Size must be one of: 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
+// Size must be one of: 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768.
func GeneratorSize(size uint16) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.size = size
+
return nil
}
}
-// GeneratorSkipLastN sets the number of packets (n-1 packets before the last received packets) to ignore when generating
-// nack requests.
+// GeneratorSkipLastN sets the number of packets (n-1 packets before the last received packets)
+//
+// to ignore when generating nack requests.
func GeneratorSkipLastN(skipLastN uint16) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.skipLastN = skipLastN
+
return nil
}
}
// GeneratorMaxNacksPerPacket sets the maximum number of NACKs sent per missing packet, e.g. if set to 2, a missing
-// packet will only be NACKed at most twice. If set to 0 (default), max number of NACKs is unlimited
+// packet will only be NACKed at most twice. If set to 0 (default), max number of NACKs is unlimited.
func GeneratorMaxNacksPerPacket(maxNacks uint16) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.maxNacksPerPacket = maxNacks
+
return nil
}
}
-// GeneratorLog sets a logger for the interceptor
+// GeneratorLog sets a logger for the interceptor.
func GeneratorLog(log logging.LeveledLogger) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.log = log
+
return nil
}
}
-// GeneratorInterval sets the nack send interval for the interceptor
+// GeneratorInterval sets the nack send interval for the interceptor.
func GeneratorInterval(interval time.Duration) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.interval = interval
+
return nil
}
}
-// GeneratorStreamsFilter sets filter for generator streams
+// GeneratorStreamsFilter sets filter for generator streams.
func GeneratorStreamsFilter(filter func(info *interceptor.StreamInfo) bool) GeneratorOption {
return func(r *GeneratorInterceptor) error {
r.streamsFilter = filter
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
index 6a19996e7..c37407d12 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/receive_log.go
@@ -6,6 +6,8 @@ package nack
import (
"fmt"
"sync"
+
+ "github.com/pion/interceptor/internal/rtpbuffer"
)
type receiveLog struct {
@@ -23,6 +25,7 @@ func newReceiveLog(size uint16) (*receiveLog, error) {
for i := 6; i < 16; i++ {
if size == 1< end (with counting for rollovers)
for i := s.end + 1; i != seq; i++ {
// clear packets between end and seq (these may contain packets from a "size" ago)
@@ -82,7 +86,7 @@ func (s *receiveLog) get(seq uint16) bool {
defer s.m.RUnlock()
diff := s.end - seq
- if diff >= uint16SizeHalf {
+ if diff >= rtpbuffer.Uint16SizeHalf {
return false
}
@@ -93,24 +97,25 @@ func (s *receiveLog) get(seq uint16) bool {
return s.getReceived(seq)
}
-func (s *receiveLog) missingSeqNumbers(skipLastN uint16) []uint16 {
+func (s *receiveLog) missingSeqNumbers(skipLastN uint16, missingPacketSeqNums []uint16) []uint16 {
s.m.RLock()
defer s.m.RUnlock()
until := s.end - skipLastN
- if until-s.lastConsecutive >= uint16SizeHalf {
+ if until-s.lastConsecutive >= rtpbuffer.Uint16SizeHalf {
// until < s.lastConsecutive (counting for rollover)
return nil
}
- missingPacketSeqNums := make([]uint16, 0)
+ c := 0
for i := s.lastConsecutive + 1; i != until+1; i++ {
if !s.getReceived(i) {
- missingPacketSeqNums = append(missingPacketSeqNums, i)
+ missingPacketSeqNums[c] = i
+ c++
}
}
- return missingPacketSeqNums
+ return missingPacketSeqNums[:c]
}
func (s *receiveLog) setReceived(seq uint16) {
@@ -125,6 +130,7 @@ func (s *receiveLog) delReceived(seq uint16) {
func (s *receiveLog) getReceived(seq uint16) bool {
pos := seq % s.size
+
return (s.packets[pos/64] & (1 << (pos % 64))) != 0
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
index 22d038ba4..8b5585ac9 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_interceptor.go
@@ -7,23 +7,20 @@ import (
"sync"
"github.com/pion/interceptor"
+ "github.com/pion/interceptor/internal/rtpbuffer"
"github.com/pion/logging"
"github.com/pion/rtcp"
"github.com/pion/rtp"
)
-// ResponderInterceptorFactory is a interceptor.Factory for a ResponderInterceptor
+// ResponderInterceptorFactory is a interceptor.Factory for a ResponderInterceptor.
type ResponderInterceptorFactory struct {
opts []ResponderOption
}
-type packetFactory interface {
- NewPacket(header *rtp.Header, payload []byte, rtxSsrc uint32, rtxPayloadType uint8) (*retainablePacket, error)
-}
-
-// NewInterceptor constructs a new ResponderInterceptor
+// NewInterceptor constructs a new ResponderInterceptor.
func (r *ResponderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &ResponderInterceptor{
+ responderInterceptor := &ResponderInterceptor{
streamsFilter: streamSupportNack,
size: 1024,
log: logging.NewDefaultLoggerFactory().NewLogger("nack_responder"),
@@ -31,40 +28,41 @@ func (r *ResponderInterceptorFactory) NewInterceptor(_ string) (interceptor.Inte
}
for _, opt := range r.opts {
- if err := opt(i); err != nil {
+ if err := opt(responderInterceptor); err != nil {
return nil, err
}
}
- if i.packetFactory == nil {
- i.packetFactory = newPacketManager()
+ if responderInterceptor.packetFactory == nil {
+ responderInterceptor.packetFactory = rtpbuffer.NewPacketFactoryCopy()
}
- if _, err := newSendBuffer(i.size); err != nil {
+ if _, err := rtpbuffer.NewRTPBuffer(responderInterceptor.size); err != nil {
return nil, err
}
- return i, nil
+ return responderInterceptor, nil
}
-// ResponderInterceptor responds to nack feedback messages
+// ResponderInterceptor responds to nack feedback messages.
type ResponderInterceptor struct {
interceptor.NoOp
streamsFilter func(info *interceptor.StreamInfo) bool
size uint16
log logging.LeveledLogger
- packetFactory packetFactory
+ packetFactory rtpbuffer.PacketFactory
streams map[uint32]*localStream
streamsMu sync.Mutex
}
type localStream struct {
- sendBuffer *sendBuffer
- rtpWriter interceptor.RTPWriter
+ rtpBuffer *rtpbuffer.RTPBuffer
+ rtpBufferMutex sync.RWMutex
+ rtpWriter interceptor.RTPWriter
}
-// NewResponderInterceptor returns a new ResponderInterceptorFactor
+// NewResponderInterceptor returns a new ResponderInterceptorFactor.
func NewResponderInterceptor(opts ...ResponderOption) (*ResponderInterceptorFactory, error) {
return &ResponderInterceptorFactory{opts}, nil
}
@@ -98,30 +96,44 @@ func (n *ResponderInterceptor) BindRTCPReader(reader interceptor.RTCPReader) int
})
}
-// BindLocalStream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method
-// will be called once per rtp packet.
-func (n *ResponderInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
+// BindLocalStream lets you modify any outgoing RTP packets. It is called once for per LocalStream.
+// The returned method will be called once per rtp packet.
+func (n *ResponderInterceptor) BindLocalStream(
+ info *interceptor.StreamInfo, writer interceptor.RTPWriter,
+) interceptor.RTPWriter {
if !n.streamsFilter(info) {
return writer
}
// error is already checked in NewGeneratorInterceptor
- sendBuffer, _ := newSendBuffer(n.size)
- n.streamsMu.Lock()
- n.streams[info.SSRC] = &localStream{
- sendBuffer: sendBuffer,
- rtpWriter: writer,
+ rtpBuffer, _ := rtpbuffer.NewRTPBuffer(n.size)
+ stream := &localStream{
+ rtpBuffer: rtpBuffer,
+ rtpWriter: writer,
}
+ n.streamsMu.Lock()
+ n.streams[info.SSRC] = stream
n.streamsMu.Unlock()
- return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
- pkt, err := n.packetFactory.NewPacket(header, payload, info.SSRCRetransmission, info.PayloadTypeRetransmission)
- if err != nil {
- return 0, err
- }
- sendBuffer.add(pkt)
- return writer.Write(header, payload, attributes)
- })
+ return interceptor.RTPWriterFunc(
+ func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
+ // If this packet doesn't belong to the main SSRC, do not add it to rtpBuffer
+ if header.SSRC != info.SSRC {
+ return writer.Write(header, payload, attributes)
+ }
+
+ pkt, err := n.packetFactory.NewPacket(header, payload, info.SSRCRetransmission, info.PayloadTypeRetransmission)
+ if err != nil {
+ return 0, err
+ }
+ stream.rtpBufferMutex.Lock()
+ defer stream.rtpBufferMutex.Unlock()
+
+ rtpBuffer.Add(pkt)
+
+ return writer.Write(header, payload, attributes)
+ },
+ )
}
// UnbindLocalStream is called when the Stream is removed. It can be used to clean up any data related to that track.
@@ -141,7 +153,10 @@ func (n *ResponderInterceptor) resendPackets(nack *rtcp.TransportLayerNack) {
for i := range nack.Nacks {
nack.Nacks[i].Range(func(seq uint16) bool {
- if p := stream.sendBuffer.get(seq); p != nil {
+ stream.rtpBufferMutex.Lock()
+ defer stream.rtpBufferMutex.Unlock()
+
+ if p := stream.rtpBuffer.Get(seq); p != nil {
if _, err := stream.rtpWriter.Write(p.Header(), p.Payload(), interceptor.Attributes{}); err != nil {
n.log.Warnf("failed resending nacked packet: %+v", err)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
index 24c7c4693..ea9435810 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/responder_option.go
@@ -5,42 +5,47 @@ package nack
import (
"github.com/pion/interceptor"
+ "github.com/pion/interceptor/internal/rtpbuffer"
"github.com/pion/logging"
)
-// ResponderOption can be used to configure ResponderInterceptor
+// ResponderOption can be used to configure ResponderInterceptor.
type ResponderOption func(s *ResponderInterceptor) error
// ResponderSize sets the size of the interceptor.
-// Size must be one of: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
+// Size must be one of: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768.
func ResponderSize(size uint16) ResponderOption {
return func(r *ResponderInterceptor) error {
r.size = size
+
return nil
}
}
-// ResponderLog sets a logger for the interceptor
+// ResponderLog sets a logger for the interceptor.
func ResponderLog(log logging.LeveledLogger) ResponderOption {
return func(r *ResponderInterceptor) error {
r.log = log
+
return nil
}
}
// DisableCopy bypasses copy of underlying packets. It should be used when
-// you are not re-using underlying buffers of packets that have been written
+// you are not re-using underlying buffers of packets that have been written.
func DisableCopy() ResponderOption {
return func(s *ResponderInterceptor) error {
- s.packetFactory = &noOpPacketFactory{}
+ s.packetFactory = &rtpbuffer.PacketFactoryNoOp{}
+
return nil
}
}
-// ResponderStreamsFilter sets filter for local streams
+// ResponderStreamsFilter sets filter for local streams.
func ResponderStreamsFilter(filter func(info *interceptor.StreamInfo) bool) ResponderOption {
return func(r *ResponderInterceptor) error {
r.streamsFilter = filter
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go
deleted file mode 100644
index 18c533a8a..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/retainable_packet.go
+++ /dev/null
@@ -1,162 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The Pion community
-// SPDX-License-Identifier: MIT
-
-package nack
-
-import (
- "encoding/binary"
- "io"
- "sync"
-
- "github.com/pion/rtp"
-)
-
-const maxPayloadLen = 1460
-
-type packetManager struct {
- headerPool *sync.Pool
- payloadPool *sync.Pool
- rtxSequencer rtp.Sequencer
-}
-
-func newPacketManager() *packetManager {
- return &packetManager{
- headerPool: &sync.Pool{
- New: func() interface{} {
- return &rtp.Header{}
- },
- },
- payloadPool: &sync.Pool{
- New: func() interface{} {
- buf := make([]byte, maxPayloadLen)
- return &buf
- },
- },
- rtxSequencer: rtp.NewRandomSequencer(),
- }
-}
-
-func (m *packetManager) NewPacket(header *rtp.Header, payload []byte, rtxSsrc uint32, rtxPayloadType uint8) (*retainablePacket, error) {
- if len(payload) > maxPayloadLen {
- return nil, io.ErrShortBuffer
- }
-
- p := &retainablePacket{
- onRelease: m.releasePacket,
- sequenceNumber: header.SequenceNumber,
- // new packets have retain count of 1
- count: 1,
- }
-
- var ok bool
- p.header, ok = m.headerPool.Get().(*rtp.Header)
- if !ok {
- return nil, errFailedToCastHeaderPool
- }
-
- *p.header = header.Clone()
-
- if payload != nil {
- p.buffer, ok = m.payloadPool.Get().(*[]byte)
- if !ok {
- return nil, errFailedToCastPayloadPool
- }
-
- size := copy(*p.buffer, payload)
- p.payload = (*p.buffer)[:size]
- }
-
- if rtxSsrc != 0 && rtxPayloadType != 0 {
- // Store the original sequence number and rewrite the sequence number.
- originalSequenceNumber := p.header.SequenceNumber
- p.header.SequenceNumber = m.rtxSequencer.NextSequenceNumber()
-
- // Rewrite the SSRC.
- p.header.SSRC = rtxSsrc
- // Rewrite the payload type.
- p.header.PayloadType = rtxPayloadType
-
- // Remove padding if present.
- paddingLength := 0
- if p.header.Padding && p.payload != nil && len(p.payload) > 0 {
- paddingLength = int(p.payload[len(p.payload)-1])
- p.header.Padding = false
- }
-
- // Write the original sequence number at the beginning of the payload.
- payload := make([]byte, 2)
- binary.BigEndian.PutUint16(payload, originalSequenceNumber)
- p.payload = append(payload, p.payload[:len(p.payload)-paddingLength]...)
- }
-
- return p, nil
-}
-
-func (m *packetManager) releasePacket(header *rtp.Header, payload *[]byte) {
- m.headerPool.Put(header)
- if payload != nil {
- m.payloadPool.Put(payload)
- }
-}
-
-type noOpPacketFactory struct{}
-
-func (f *noOpPacketFactory) NewPacket(header *rtp.Header, payload []byte, _ uint32, _ uint8) (*retainablePacket, error) {
- return &retainablePacket{
- onRelease: f.releasePacket,
- count: 1,
- header: header,
- payload: payload,
- sequenceNumber: header.SequenceNumber,
- }, nil
-}
-
-func (f *noOpPacketFactory) releasePacket(_ *rtp.Header, _ *[]byte) {
- // no-op
-}
-
-type retainablePacket struct {
- onRelease func(*rtp.Header, *[]byte)
-
- countMu sync.Mutex
- count int
-
- header *rtp.Header
- buffer *[]byte
- payload []byte
-
- sequenceNumber uint16
-}
-
-func (p *retainablePacket) Header() *rtp.Header {
- return p.header
-}
-
-func (p *retainablePacket) Payload() []byte {
- return p.payload
-}
-
-func (p *retainablePacket) Retain() error {
- p.countMu.Lock()
- defer p.countMu.Unlock()
- if p.count == 0 {
- // already released
- return errPacketReleased
- }
- p.count++
- return nil
-}
-
-func (p *retainablePacket) Release() {
- p.countMu.Lock()
- defer p.countMu.Unlock()
- p.count--
-
- if p.count == 0 {
- // release back to pool
- p.onRelease(p.header, p.buffer)
- p.header = nil
- p.buffer = nil
- p.payload = nil
- }
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go
deleted file mode 100644
index 2b3b076f5..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/nack/send_buffer.go
+++ /dev/null
@@ -1,104 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The Pion community
-// SPDX-License-Identifier: MIT
-
-package nack
-
-import (
- "fmt"
- "sync"
-)
-
-const (
- uint16SizeHalf = 1 << 15
-)
-
-type sendBuffer struct {
- packets []*retainablePacket
- size uint16
- lastAdded uint16
- started bool
-
- m sync.RWMutex
-}
-
-func newSendBuffer(size uint16) (*sendBuffer, error) {
- allowedSizes := make([]uint16, 0)
- correctSize := false
- for i := 0; i < 16; i++ {
- if size == 1<= uint16SizeHalf {
- return nil
- }
-
- if diff >= s.size {
- return nil
- }
-
- pkt := s.packets[seq%s.size]
- if pkt != nil {
- if pkt.sequenceNumber != seq {
- return nil
- }
- // already released
- if err := pkt.Retain(); err != nil {
- return nil
- }
- }
- return pkt
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
index 0afbd08f5..91b513c55 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_interceptor.go
@@ -12,14 +12,14 @@ import (
"github.com/pion/rtcp"
)
-// ReceiverInterceptorFactory is a interceptor.Factory for a ReceiverInterceptor
+// ReceiverInterceptorFactory is a interceptor.Factory for a ReceiverInterceptor.
type ReceiverInterceptorFactory struct {
opts []ReceiverOption
}
-// NewInterceptor constructs a new ReceiverInterceptor
+// NewInterceptor constructs a new ReceiverInterceptor.
func (r *ReceiverInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &ReceiverInterceptor{
+ receiverInterceptor := &ReceiverInterceptor{
interval: 1 * time.Second,
now: time.Now,
log: logging.NewDefaultLoggerFactory().NewLogger("receiver_interceptor"),
@@ -27,15 +27,15 @@ func (r *ReceiverInterceptorFactory) NewInterceptor(_ string) (interceptor.Inter
}
for _, opt := range r.opts {
- if err := opt(i); err != nil {
+ if err := opt(receiverInterceptor); err != nil {
return nil, err
}
}
- return i, nil
+ return receiverInterceptor, nil
}
-// NewReceiverInterceptor returns a new ReceiverInterceptorFactory
+// NewReceiverInterceptor returns a new ReceiverInterceptorFactory.
func NewReceiverInterceptor(opts ...ReceiverOption) (*ReceiverInterceptorFactory, error) {
return &ReceiverInterceptorFactory{opts}, nil
}
@@ -103,7 +103,9 @@ func (r *ReceiverInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
r.streams.Range(func(_, value interface{}) bool {
if stream, ok := value.(*receiverStream); !ok {
r.log.Warnf("failed to cast ReceiverInterceptor stream")
- } else if _, err := rtcpWriter.Write([]rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{}); err != nil {
+ } else if _, err := rtcpWriter.Write(
+ []rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{},
+ ); err != nil {
r.log.Warnf("failed sending: %+v", err)
}
@@ -116,9 +118,11 @@ func (r *ReceiverInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
}
}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
-// will be called once per rtp packet.
-func (r *ReceiverInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
+// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream.
+// The returned method will be called once per rtp packet.
+func (r *ReceiverInterceptor) BindRemoteStream(
+ info *interceptor.StreamInfo, reader interceptor.RTPReader,
+) interceptor.RTPReader {
stream := newReceiverStream(info.SSRC, info.ClockRate)
r.streams.Store(info.SSRC, stream)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
index 337a34142..4a91561d9 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_option.go
@@ -16,6 +16,7 @@ type ReceiverOption func(r *ReceiverInterceptor) error
func ReceiverLog(log logging.LeveledLogger) ReceiverOption {
return func(r *ReceiverInterceptor) error {
r.log = log
+
return nil
}
}
@@ -24,6 +25,7 @@ func ReceiverLog(log logging.LeveledLogger) ReceiverOption {
func ReceiverInterval(interval time.Duration) ReceiverOption {
return func(r *ReceiverInterceptor) error {
r.interval = interval
+
return nil
}
}
@@ -32,6 +34,7 @@ func ReceiverInterval(interval time.Duration) ReceiverOption {
func ReceiverNow(f func() time.Time) ReceiverOption {
return func(r *ReceiverInterceptor) error {
r.now = f
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
index ebe08473d..92913538b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/receiver_stream.go
@@ -41,6 +41,7 @@ type receiverStream struct {
func newReceiverStream(ssrc uint32, clockRate uint32) *receiverStream {
receiverSSRC := rand.Uint32() // #nosec
+
return &receiverStream{
ssrc: ssrc,
receiverSSRC: receiverSSRC,
@@ -54,6 +55,7 @@ func (stream *receiverStream) processRTP(now time.Time, pktHeader *rtp.Header) {
stream.m.Lock()
defer stream.m.Unlock()
+ //nolint:nestif
if !stream.started { // first frame
stream.started = true
stream.setReceived(pktHeader.SequenceNumber)
@@ -104,6 +106,7 @@ func (stream *receiverStream) delReceived(seq uint16) {
func (stream *receiverStream) getReceived(seq uint16) bool {
pos := seq % (stream.size * packetsPerHistoryEntry)
+
return (stream.packets[pos/packetsPerHistoryEntry] & (1 << (pos % packetsPerHistoryEntry))) != 0
}
@@ -111,7 +114,7 @@ func (stream *receiverStream) processSenderReport(now time.Time, sr *rtcp.Sender
stream.m.Lock()
defer stream.m.Unlock()
- stream.lastSenderReport = uint32(sr.NTPTime >> 16)
+ stream.lastSenderReport = uint32(sr.NTPTime >> 16) //nolint:gosec // G115
stream.lastSenderReportTime = now
}
@@ -131,6 +134,7 @@ func (stream *receiverStream) generateReport(now time.Time) *rtcp.ReceiverReport
ret++
}
}
+
return ret
}()
stream.totalLost += totalLostSinceReport
@@ -143,7 +147,7 @@ func (stream *receiverStream) generateReport(now time.Time) *rtcp.ReceiverReport
stream.totalLost = 0xFFFFFF
}
- r := &rtcp.ReceiverReport{
+ receiverReport := &rtcp.ReceiverReport{
SSRC: stream.receiverSSRC,
Reports: []rtcp.ReceptionReport{
{
@@ -156,6 +160,7 @@ func (stream *receiverStream) generateReport(now time.Time) *rtcp.ReceiverReport
if stream.lastSenderReportTime.IsZero() {
return 0
}
+
return uint32(now.Sub(stream.lastSenderReportTime).Seconds() * 65536)
}(),
Jitter: uint32(stream.jitter),
@@ -165,5 +170,5 @@ func (stream *receiverStream) generateReport(now time.Time) *rtcp.ReceiverReport
stream.lastReportSeqnum = stream.lastSeqnum
- return r
+ return receiverReport
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
index 1b6f4b252..40c7f9f7a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_interceptor.go
@@ -13,17 +13,17 @@ import (
"github.com/pion/rtp"
)
-// TickerFactory is a factory to create new tickers
+// TickerFactory is a factory to create new tickers.
type TickerFactory func(d time.Duration) Ticker
-// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor
+// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor.
type SenderInterceptorFactory struct {
opts []SenderOption
}
-// NewInterceptor constructs a new SenderInterceptor
+// NewInterceptor constructs a new SenderInterceptor.
func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &SenderInterceptor{
+ senderInterceptor := &SenderInterceptor{
interval: 1 * time.Second,
now: time.Now,
newTicker: func(d time.Duration) Ticker {
@@ -34,15 +34,15 @@ func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interce
}
for _, opt := range s.opts {
- if err := opt(i); err != nil {
+ if err := opt(senderInterceptor); err != nil {
return nil, err
}
}
- return i, nil
+ return senderInterceptor, nil
}
-// NewSenderInterceptor returns a new SenderInterceptorFactory
+// NewSenderInterceptor returns a new SenderInterceptorFactory.
func NewSenderInterceptor(opts ...SenderOption) (*SenderInterceptorFactory, error) {
return &SenderInterceptorFactory{opts}, nil
}
@@ -119,7 +119,9 @@ func (s *SenderInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
s.streams.Range(func(_, value interface{}) bool {
if stream, ok := value.(*senderStream); !ok {
s.log.Warnf("failed to cast SenderInterceptor stream")
- } else if _, err := rtcpWriter.Write([]rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{}); err != nil {
+ } else if _, err := rtcpWriter.Write(
+ []rtcp.Packet{stream.generateReport(now)}, interceptor.Attributes{},
+ ); err != nil {
s.log.Warnf("failed sending: %+v", err)
}
@@ -134,7 +136,9 @@ func (s *SenderInterceptor) loop(rtcpWriter interceptor.RTCPWriter) {
// BindLocalStream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method
// will be called once per rtp packet.
-func (s *SenderInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
+func (s *SenderInterceptor) BindLocalStream(
+ info *interceptor.StreamInfo, writer interceptor.RTPWriter,
+) interceptor.RTPWriter {
stream := newSenderStream(info.SSRC, info.ClockRate, s.useLatestPacket)
s.streams.Store(info.SSRC, stream)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
index 1e489b0b3..07a4f0875 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_option.go
@@ -16,6 +16,7 @@ type SenderOption func(r *SenderInterceptor) error
func SenderLog(log logging.LeveledLogger) SenderOption {
return func(r *SenderInterceptor) error {
r.log = log
+
return nil
}
}
@@ -24,6 +25,7 @@ func SenderLog(log logging.LeveledLogger) SenderOption {
func SenderInterval(interval time.Duration) SenderOption {
return func(r *SenderInterceptor) error {
r.interval = interval
+
return nil
}
}
@@ -32,6 +34,7 @@ func SenderInterval(interval time.Duration) SenderOption {
func SenderNow(f func() time.Time) SenderOption {
return func(r *SenderInterceptor) error {
r.now = f
+
return nil
}
}
@@ -40,6 +43,7 @@ func SenderNow(f func() time.Time) SenderOption {
func SenderTicker(f TickerFactory) SenderOption {
return func(r *SenderInterceptor) error {
r.newTicker = f
+
return nil
}
}
@@ -49,6 +53,7 @@ func SenderTicker(f TickerFactory) SenderOption {
func SenderUseLatestPacket() SenderOption {
return func(r *SenderInterceptor) error {
r.useLatestPacket = true
+
return nil
}
}
@@ -58,6 +63,7 @@ func SenderUseLatestPacket() SenderOption {
func enableStartTracking(startedCh chan struct{}) SenderOption {
return func(r *SenderInterceptor) error {
r.started = startedCh
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_stream.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_stream.go
index 44658e246..6bb37dbff 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_stream.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/report/sender_stream.go
@@ -48,7 +48,7 @@ func (stream *senderStream) processRTP(now time.Time, header *rtp.Header, payloa
}
stream.packetCount++
- stream.octetCount += uint32(len(payload))
+ stream.octetCount += uint32(len(payload)) //nolint:gosec // G115
}
func (stream *senderStream) generateReport(now time.Time) *rtcp.SenderReport {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/interceptor.go
index efe2df29c..344ec1be1 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/interceptor.go
@@ -14,17 +14,17 @@ import (
"github.com/pion/rtcp"
)
-// TickerFactory is a factory to create new tickers
+// TickerFactory is a factory to create new tickers.
type TickerFactory func(d time.Duration) ticker
-// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor
+// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor.
type SenderInterceptorFactory struct {
opts []Option
}
-// NewInterceptor constructs a new SenderInterceptor
+// NewInterceptor constructs a new SenderInterceptor.
func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &SenderInterceptor{
+ senderInterceptor := &SenderInterceptor{
NoOp: interceptor.NoOp{},
log: logging.NewDefaultLoggerFactory().NewLogger("rfc8888_interceptor"),
lock: sync.Mutex{},
@@ -40,12 +40,13 @@ func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interce
close: make(chan struct{}),
}
for _, opt := range s.opts {
- err := opt(i)
+ err := opt(senderInterceptor)
if err != nil {
return nil, err
}
}
- return i, nil
+
+ return senderInterceptor, nil
}
// NewSenderInterceptor returns a new SenderInterceptorFactory configured with the given options.
@@ -91,9 +92,12 @@ func (s *SenderInterceptor) BindRTCPWriter(writer interceptor.RTCPWriter) interc
return writer
}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
-// will be called once per rtp packet.
-func (s *SenderInterceptor) BindRemoteStream(_ *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
+// BindRemoteStream lets you modify any incoming RTP packets.
+// It is called once for per RemoteStream. The returned method
+// will be called once per rtp packet..
+func (s *SenderInterceptor) BindRemoteStream(
+ _ *interceptor.StreamInfo, reader interceptor.RTPReader,
+) interceptor.RTPReader {
return interceptor.RTPReaderFunc(func(b []byte, a interceptor.Attributes) (int, interceptor.Attributes, error) {
i, attr, err := reader.Read(b, a)
if err != nil {
@@ -115,6 +119,7 @@ func (s *SenderInterceptor) BindRemoteStream(_ *interceptor.StreamInfo, reader i
ecn: 0, // ECN is not supported (yet).
}
s.packetChan <- p
+
return i, attr, nil
})
}
@@ -157,16 +162,19 @@ func (s *SenderInterceptor) loop(writer interceptor.RTCPWriter) {
select {
case <-s.close:
t.Stop()
+
return
case pkt := <-s.packetChan:
s.log.Tracef("got packet: %v", pkt)
s.recorder.AddPacket(pkt.arrival, pkt.ssrc, pkt.sequenceNumber, pkt.ecn)
- case now := <-t.Ch():
+ case <-t.Ch():
+ now := s.now()
s.log.Tracef("report triggered at %v", now)
if writer == nil {
s.log.Trace("no writer added, continue")
+
continue
}
pkts := s.recorder.BuildReport(now, int(s.maxReportSize))
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/option.go
index 1214868bf..236073b5d 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/option.go
@@ -5,13 +5,14 @@ package rfc8888
import "time"
-// An Option is a function that can be used to configure a SenderInterceptor
+// An Option is a function that can be used to configure a SenderInterceptor.
type Option func(*SenderInterceptor) error
// SenderTicker sets an alternative for time.Ticker.
func SenderTicker(f TickerFactory) Option {
return func(i *SenderInterceptor) error {
i.newTicker = f
+
return nil
}
}
@@ -20,14 +21,16 @@ func SenderTicker(f TickerFactory) Option {
func SenderNow(f func() time.Time) Option {
return func(i *SenderInterceptor) error {
i.now = f
+
return nil
}
}
-// SendInterval sets the feedback send interval for the interceptor
+// SendInterval sets the feedback send interval for the interceptor.
func SendInterval(interval time.Duration) Option {
return func(s *SenderInterceptor) error {
s.interval = interval
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/recorder.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/recorder.go
index 4423df1e3..a1a2cf266 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/recorder.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/recorder.go
@@ -6,6 +6,7 @@ package rfc8888
import (
"time"
+ "github.com/pion/interceptor/internal/ntp"
"github.com/pion/rtcp"
)
@@ -21,7 +22,7 @@ type Recorder struct {
streams map[uint32]*streamLog
}
-// NewRecorder creates a new Recorder
+// NewRecorder creates a new Recorder.
func NewRecorder() *Recorder {
return &Recorder{
streams: map[uint32]*streamLog{},
@@ -44,7 +45,7 @@ func (r *Recorder) BuildReport(now time.Time, maxSize int) *rtcp.CCFeedbackRepor
report := &rtcp.CCFeedbackReport{
SenderSSRC: r.ssrc,
ReportBlocks: []rtcp.CCFeedbackReportBlock{},
- ReportTimestamp: ntpTime32(now),
+ ReportTimestamp: ntp.ToNTP32(now),
}
maxReportBlocks := (maxSize - 12 - (8 * len(r.streams))) / 2
@@ -65,14 +66,3 @@ func (r *Recorder) BuildReport(now time.Time, maxSize int) *rtcp.CCFeedbackRepor
return report
}
-
-func ntpTime32(t time.Time) uint32 {
- // seconds since 1st January 1900
- s := (float64(t.UnixNano()) / 1000000000.0) + 2208988800
-
- integerPart := uint32(s)
- fractionalPart := uint32((s - float64(integerPart)) * 0xFFFFFFFF)
-
- // higher 32 bits are the integer part, lower 32 bits are the fractional part
- return uint32(((uint64(integerPart)<<32 | uint64(fractionalPart)) >> 16) & 0xFFFFFFFF)
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/stream_log.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/stream_log.go
index 8dfb14fc9..ed41f9528 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/stream_log.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/stream_log.go
@@ -6,6 +6,7 @@ package rfc8888
import (
"time"
+ "github.com/pion/interceptor/internal/sequencenumber"
"github.com/pion/rtcp"
)
@@ -13,7 +14,7 @@ const maxReportsPerReportBlock = 16384
type streamLog struct {
ssrc uint32
- sequence unwrapper
+ sequence sequencenumber.Unwrapper
init bool
nextSequenceNumberToReport int64 // next to report
lastSequenceNumberReceived int64 // highest received
@@ -23,7 +24,7 @@ type streamLog struct {
func newStreamLog(ssrc uint32) *streamLog {
return &streamLog{
ssrc: ssrc,
- sequence: unwrapper{},
+ sequence: sequencenumber.Unwrapper{},
init: false,
nextSequenceNumberToReport: 0,
lastSequenceNumberReceived: 0,
@@ -32,7 +33,7 @@ func newStreamLog(ssrc uint32) *streamLog {
}
func (l *streamLog) add(ts time.Time, sequenceNumber uint16, ecn uint8) {
- unwrappedSequenceNumber := l.sequence.unwrap(sequenceNumber)
+ unwrappedSequenceNumber := l.sequence.Unwrap(sequenceNumber)
if !l.init {
l.init = true
l.nextSequenceNumberToReport = unwrappedSequenceNumber
@@ -52,7 +53,7 @@ func (l *streamLog) metricsAfter(reference time.Time, maxReportBlocks int64) rtc
if len(l.log) == 0 {
return rtcp.CCFeedbackReportBlock{
MediaSSRC: l.ssrc,
- BeginSequence: uint16(l.nextSequenceNumberToReport),
+ BeginSequence: uint16(l.nextSequenceNumberToReport), //nolint:gosec // G115
MetricBlocks: []rtcp.CCFeedbackMetricBlock{},
}
}
@@ -65,7 +66,7 @@ func (l *streamLog) metricsAfter(reference time.Time, maxReportBlocks int64) rtc
offset := l.nextSequenceNumberToReport
lastReceived := l.nextSequenceNumberToReport
gapDetected := false
- for i := offset; i <= l.lastSequenceNumberReceived; i++ {
+ for i := offset; i <= l.lastSequenceNumberReceived; i++ { //nolint:varnamelen // i int64
received := false
ecn := uint8(0)
ato := uint16(0)
@@ -91,9 +92,10 @@ func (l *streamLog) metricsAfter(reference time.Time, maxReportBlocks int64) rtc
}
}
}
+
return rtcp.CCFeedbackReportBlock{
MediaSSRC: l.ssrc,
- BeginSequence: uint16(offset),
+ BeginSequence: uint16(offset), //nolint:gosec // G115
MetricBlocks: metricBlocks,
}
}
@@ -106,5 +108,6 @@ func getArrivalTimeOffset(base time.Time, arrival time.Time) uint16 {
if ato > 0x1FFD {
return 0x1FFE
}
+
return ato
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/unwrapper.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/unwrapper.go
deleted file mode 100644
index f15f33e6e..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/rfc8888/unwrapper.go
+++ /dev/null
@@ -1,42 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The Pion community
-// SPDX-License-Identifier: MIT
-
-package rfc8888
-
-const (
- maxSequenceNumberPlusOne = int64(65536)
- breakpoint = 32768 // half of max uint16
-)
-
-type unwrapper struct {
- init bool
- lastUnwrapped int64
-}
-
-func isNewer(value, previous uint16) bool {
- if value-previous == breakpoint {
- return value > previous
- }
- return value != previous && (value-previous) < breakpoint
-}
-
-func (u *unwrapper) unwrap(i uint16) int64 {
- if !u.init {
- u.init = true
- u.lastUnwrapped = int64(i)
- return u.lastUnwrapped
- }
-
- lastWrapped := uint16(u.lastUnwrapped)
- delta := int64(i - lastWrapped)
- if isNewer(i, lastWrapped) {
- if delta < 0 {
- delta += maxSequenceNumberPlusOne
- }
- } else if delta > 0 && u.lastUnwrapped+delta-maxSequenceNumberPlusOne >= 0 {
- delta -= maxSequenceNumberPlusOne
- }
-
- u.lastUnwrapped += delta
- return u.lastUnwrapped
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/arrival_time_map.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/arrival_time_map.go
index d3e2a8af3..a496ad73c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/arrival_time_map.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/arrival_time_map.go
@@ -12,6 +12,8 @@ const (
// of the arrival times of packets. It is used by the TWCC interceptor to build feedback
// packets.
// See https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/webrtc/modules/remote_bitrate_estimator/packet_arrival_map.h;drc=b5cd13bb6d5d157a5fbe3628b2dd1c1e106203c6
+//
+//nolint:lll
type packetArrivalTimeMap struct {
// arrivalTimes is a circular buffer, where the packet with sequence number sn is stored
// in slot sn % len(arrivalTimes)
@@ -31,12 +33,14 @@ func (m *packetArrivalTimeMap) AddPacket(sequenceNumber int64, arrivalTime int64
m.beginSequenceNumber = sequenceNumber
m.endSequenceNumber = sequenceNumber + 1
m.arrivalTimes[m.index(sequenceNumber)] = arrivalTime
+
return
}
if sequenceNumber >= m.beginSequenceNumber && sequenceNumber < m.endSequenceNumber {
// The packet is within the buffer, no need to resize.
m.arrivalTimes[m.index(sequenceNumber)] = arrivalTime
+
return
}
@@ -53,6 +57,7 @@ func (m *packetArrivalTimeMap) AddPacket(sequenceNumber int64, arrivalTime int64
m.arrivalTimes[m.index(sequenceNumber)] = arrivalTime
m.setNotReceived(sequenceNumber+1, m.beginSequenceNumber)
m.beginSequenceNumber = sequenceNumber
+
return
}
@@ -64,6 +69,7 @@ func (m *packetArrivalTimeMap) AddPacket(sequenceNumber int64, arrivalTime int64
m.beginSequenceNumber = sequenceNumber
m.endSequenceNumber = newEndSequenceNumber
m.arrivalTimes[m.index(sequenceNumber)] = arrivalTime
+
return
}
@@ -99,12 +105,15 @@ func (m *packetArrivalTimeMap) EndSequenceNumber() int64 {
// FindNextAtOrAfter returns the sequence number and timestamp of the first received packet that has a sequence number
// greator or equal to sequenceNumber.
-func (m *packetArrivalTimeMap) FindNextAtOrAfter(sequenceNumber int64) (foundSequenceNumber int64, arrivalTime int64, ok bool) {
+func (m *packetArrivalTimeMap) FindNextAtOrAfter(sequenceNumber int64) (
+ foundSequenceNumber int64, arrivalTime int64, ok bool,
+) {
for sequenceNumber = m.Clamp(sequenceNumber); sequenceNumber < m.endSequenceNumber; sequenceNumber++ {
if t := m.get(sequenceNumber); t >= 0 {
return sequenceNumber, t, true
}
}
+
return -1, -1, false
}
@@ -116,6 +125,7 @@ func (m *packetArrivalTimeMap) EraseTo(sequenceNumber int64) {
if sequenceNumber >= m.endSequenceNumber {
// Erase all.
m.beginSequenceNumber = m.endSequenceNumber
+
return
}
// Remove some
@@ -138,7 +148,7 @@ func (m *packetArrivalTimeMap) HasReceived(sequenceNumber int64) bool {
return m.get(sequenceNumber) >= 0
}
-// Clamp returns sequenceNumber clamped to [beginSequenceNumber, endSequenceNumber]
+// Clamp returns sequenceNumber clamped to [beginSequenceNumber, endSequenceNumber].
func (m *packetArrivalTimeMap) Clamp(sequenceNumber int64) int64 {
if sequenceNumber < m.beginSequenceNumber {
return m.beginSequenceNumber
@@ -146,6 +156,7 @@ func (m *packetArrivalTimeMap) Clamp(sequenceNumber int64) int64 {
if m.endSequenceNumber < sequenceNumber {
return m.endSequenceNumber
}
+
return sequenceNumber
}
@@ -153,6 +164,7 @@ func (m *packetArrivalTimeMap) get(sequenceNumber int64) int64 {
if sequenceNumber < m.beginSequenceNumber || sequenceNumber >= m.endSequenceNumber {
return -1
}
+
return m.arrivalTimes[m.index(sequenceNumber)]
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/header_extension_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/header_extension_interceptor.go
index 791b14592..52d9e84aa 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/header_extension_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/header_extension_interceptor.go
@@ -13,20 +13,20 @@ import (
var errHeaderIsNil = errors.New("header is nil")
-// HeaderExtensionInterceptorFactory is a interceptor.Factory for a HeaderExtensionInterceptor
+// HeaderExtensionInterceptorFactory is a interceptor.Factory for a HeaderExtensionInterceptor.
type HeaderExtensionInterceptorFactory struct{}
-// NewInterceptor constructs a new HeaderExtensionInterceptor
+// NewInterceptor constructs a new HeaderExtensionInterceptor.
func (h *HeaderExtensionInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
return &HeaderExtensionInterceptor{}, nil
}
-// NewHeaderExtensionInterceptor returns a HeaderExtensionInterceptorFactory
+// NewHeaderExtensionInterceptor returns a HeaderExtensionInterceptorFactory.
func NewHeaderExtensionInterceptor() (*HeaderExtensionInterceptorFactory, error) {
return &HeaderExtensionInterceptorFactory{}, nil
}
-// HeaderExtensionInterceptor adds transport wide sequence numbers as header extension to each RTP packet
+// HeaderExtensionInterceptor adds transport wide sequence numbers as header extension to each RTP packet.
type HeaderExtensionInterceptor struct {
interceptor.NoOp
nextSequenceNr uint32
@@ -36,31 +36,39 @@ const transportCCURI = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide
// BindLocalStream returns a writer that adds a rtp.TransportCCExtension
// header with increasing sequence numbers to each outgoing packet.
-func (h *HeaderExtensionInterceptor) BindLocalStream(info *interceptor.StreamInfo, writer interceptor.RTPWriter) interceptor.RTPWriter {
+func (h *HeaderExtensionInterceptor) BindLocalStream(
+ info *interceptor.StreamInfo,
+ writer interceptor.RTPWriter,
+) interceptor.RTPWriter {
var hdrExtID uint8
for _, e := range info.RTPHeaderExtensions {
if e.URI == transportCCURI {
- hdrExtID = uint8(e.ID)
+ hdrExtID = uint8(e.ID) //nolint:gosec // G115
+
break
}
}
if hdrExtID == 0 { // Don't add header extension if ID is 0, because 0 is an invalid extension ID
return writer
}
- return interceptor.RTPWriterFunc(func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
- sequenceNumber := atomic.AddUint32(&h.nextSequenceNr, 1) - 1
- tcc, err := (&rtp.TransportCCExtension{TransportSequence: uint16(sequenceNumber)}).Marshal()
- if err != nil {
- return 0, err
- }
- if header == nil {
- return 0, errHeaderIsNil
- }
- err = header.SetExtension(hdrExtID, tcc)
- if err != nil {
- return 0, err
- }
- return writer.Write(header, payload, attributes)
- })
+ return interceptor.RTPWriterFunc(
+ func(header *rtp.Header, payload []byte, attributes interceptor.Attributes) (int, error) {
+ sequenceNumber := atomic.AddUint32(&h.nextSequenceNr, 1) - 1
+ //nolint:gosec // G115
+ tcc, err := (&rtp.TransportCCExtension{TransportSequence: uint16(sequenceNumber)}).Marshal()
+ if err != nil {
+ return 0, err
+ }
+ if header == nil {
+ return 0, errHeaderIsNil
+ }
+ err = header.SetExtension(hdrExtID, tcc)
+ if err != nil {
+ return 0, err
+ }
+
+ return writer.Write(header, payload, attributes)
+ },
+ )
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/sender_interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/sender_interceptor.go
index d7906fc68..229330ad4 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/sender_interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/sender_interceptor.go
@@ -14,16 +14,16 @@ import (
"github.com/pion/rtp"
)
-// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor
+// SenderInterceptorFactory is a interceptor.Factory for a SenderInterceptor.
type SenderInterceptorFactory struct {
opts []Option
}
var errClosed = errors.New("interceptor is closed")
-// NewInterceptor constructs a new SenderInterceptor
+// NewInterceptor constructs a new SenderInterceptor.
func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interceptor, error) {
- i := &SenderInterceptor{
+ senderInterceptor := &SenderInterceptor{
log: logging.NewDefaultLoggerFactory().NewLogger("twcc_sender_interceptor"),
packetChan: make(chan packet),
close: make(chan struct{}),
@@ -32,13 +32,13 @@ func (s *SenderInterceptorFactory) NewInterceptor(_ string) (interceptor.Interce
}
for _, opt := range s.opts {
- err := opt(i)
+ err := opt(senderInterceptor)
if err != nil {
return nil, err
}
}
- return i, nil
+ return senderInterceptor, nil
}
// NewSenderInterceptor returns a new SenderInterceptorFactory configured with the given options.
@@ -64,7 +64,7 @@ type SenderInterceptor struct {
packetChan chan packet
}
-// An Option is a function that can be used to configure a SenderInterceptor
+// An Option is a function that can be used to configure a SenderInterceptor.
type Option func(*SenderInterceptor) error
// SendInterval sets the interval at which the interceptor
@@ -72,6 +72,7 @@ type Option func(*SenderInterceptor) error
func SendInterval(interval time.Duration) Option {
return func(s *SenderInterceptor) error {
s.interval = interval
+
return nil
}
}
@@ -102,54 +103,63 @@ type packet struct {
ssrc uint32
}
-// BindRemoteStream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
+// BindRemoteStream lets you modify any incoming RTP packets.
+// It is called once for per RemoteStream. The returned method
// will be called once per rtp packet.
-func (s *SenderInterceptor) BindRemoteStream(info *interceptor.StreamInfo, reader interceptor.RTPReader) interceptor.RTPReader {
+//
+//nolint:cyclop
+func (s *SenderInterceptor) BindRemoteStream(
+ info *interceptor.StreamInfo, reader interceptor.RTPReader,
+) interceptor.RTPReader {
var hdrExtID uint8
for _, e := range info.RTPHeaderExtensions {
if e.URI == transportCCURI {
- hdrExtID = uint8(e.ID)
+ hdrExtID = uint8(e.ID) //nolint:gosec // G115
+
break
}
}
if hdrExtID == 0 { // Don't try to read header extension if ID is 0, because 0 is an invalid extension ID
return reader
}
- return interceptor.RTPReaderFunc(func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
- i, attr, err := reader.Read(buf, attributes)
- if err != nil {
- return 0, nil, err
- }
- if attr == nil {
- attr = make(interceptor.Attributes)
- }
- header, err := attr.GetRTPHeader(buf[:i])
- if err != nil {
- return 0, nil, err
- }
- var tccExt rtp.TransportCCExtension
- if ext := header.GetExtension(hdrExtID); ext != nil {
- err = tccExt.Unmarshal(ext)
+ return interceptor.RTPReaderFunc(
+ func(buf []byte, attributes interceptor.Attributes) (int, interceptor.Attributes, error) {
+ i, attr, err := reader.Read(buf, attributes)
if err != nil {
return 0, nil, err
}
- p := packet{
- hdr: header,
- sequenceNumber: tccExt.TransportSequence,
- arrivalTime: time.Since(s.startTime).Microseconds(),
- ssrc: info.SSRC,
+ if attr == nil {
+ attr = make(interceptor.Attributes)
}
- select {
- case <-s.close:
- return 0, nil, errClosed
- case s.packetChan <- p:
+ header, err := attr.GetRTPHeader(buf[:i])
+ if err != nil {
+ return 0, nil, err
}
- }
+ var tccExt rtp.TransportCCExtension
+ if ext := header.GetExtension(hdrExtID); ext != nil {
+ err = tccExt.Unmarshal(ext)
+ if err != nil {
+ return 0, nil, err
+ }
- return i, attr, nil
- })
+ p := packet{
+ hdr: header,
+ sequenceNumber: tccExt.TransportSequence,
+ arrivalTime: time.Since(s.startTime).Microseconds(),
+ ssrc: info.SSRC,
+ }
+ select {
+ case <-s.close:
+ return 0, nil, errClosed
+ case s.packetChan <- p:
+ }
+ }
+
+ return i, attr, nil
+ },
+ )
}
// Close closes the interceptor.
@@ -174,7 +184,7 @@ func (s *SenderInterceptor) isClosed() bool {
}
}
-func (s *SenderInterceptor) loop(w interceptor.RTCPWriter) {
+func (s *SenderInterceptor) loop(writer interceptor.RTCPWriter) {
defer s.wg.Done()
select {
@@ -189,6 +199,7 @@ func (s *SenderInterceptor) loop(w interceptor.RTCPWriter) {
select {
case <-s.close:
ticker.Stop()
+
return
case p := <-s.packetChan:
s.recorder.Record(p.ssrc, p.sequenceNumber, p.arrivalTime)
@@ -199,7 +210,7 @@ func (s *SenderInterceptor) loop(w interceptor.RTCPWriter) {
if len(pkts) == 0 {
continue
}
- if _, err := w.Write(pkts, nil); err != nil {
+ if _, err := writer.Write(pkts, nil); err != nil {
s.log.Error(err.Error())
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/twcc.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/twcc.go
index 6464c77bc..750e4541d 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/twcc.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/pkg/twcc/twcc.go
@@ -71,12 +71,13 @@ func (r *Recorder) Record(mediaSSRC uint32, sequenceNumber uint16, arrivalTime i
}
func (r *Recorder) maybeCullOldPackets(sequenceNumber int64, arrivalTime int64) {
- if r.startSequenceNumber != nil && *r.startSequenceNumber >= r.arrivalTimeMap.EndSequenceNumber() && arrivalTime >= packetWindowMicroseconds {
+ if r.startSequenceNumber != nil && *r.startSequenceNumber >= r.arrivalTimeMap.EndSequenceNumber() &&
+ arrivalTime >= packetWindowMicroseconds {
r.arrivalTimeMap.RemoveOldPackets(sequenceNumber, arrivalTime-packetWindowMicroseconds)
}
}
-// PacketsHeld returns the number of received packets currently held by the recorder
+// PacketsHeld returns the number of received packets currently held by the recorder.
func (r *Recorder) PacketsHeld() int {
return r.packetsHeld
}
@@ -101,6 +102,7 @@ func (r *Recorder) BuildFeedbackPacket() []rtcp.Packet {
// old.
}
r.packetsHeld = 0
+
return feedbacks
}
@@ -109,6 +111,7 @@ func (r *Recorder) BuildFeedbackPacket() []rtcp.Packet {
func (r *Recorder) maybeBuildFeedbackPacket(beginSeqNumInclusive, endSeqNumExclusive int64) *feedback {
// NOTE: The logic of this method is inspired by the implementation in Chrome.
// See https://source.chromium.org/chromium/chromium/src/+/refs/heads/main:third_party/webrtc/modules/remote_bitrate_estimator/remote_estimator_proxy.cc;l=276;drc=b5cd13bb6d5d157a5fbe3628b2dd1c1e106203c6
+ //nolint:lll
startSNInclusive, endSNExclusive := r.arrivalTimeMap.Clamp(beginSeqNumInclusive), r.arrivalTimeMap.Clamp(endSeqNumExclusive)
// Create feedback on demand, as we don't yet know if there are packets in the range that have been
@@ -136,18 +139,19 @@ func (r *Recorder) maybeBuildFeedbackPacket(beginSeqNumInclusive, endSeqNumExclu
// baseSequenceNumber is the expected first sequence number. This is known,
// but we may not have actually received it, so the base time should be the time
// of the first received packet in the feedback.
- fb.setBase(uint16(baseSequenceNumber), arrivalTime)
+ fb.setBase(uint16(baseSequenceNumber), arrivalTime) //nolint:gosec // G115
- if !fb.addReceived(uint16(seq), arrivalTime) {
+ if !fb.addReceived(uint16(seq), arrivalTime) { //nolint:gosec // G115
// Could not add a single received packet to the feedback.
// This is unexpected to actually occur, but if it does, we'll
// try again after skipping any missing packets.
// NOTE: It's fine that we already incremented fbPktCnt, as in essence
// we did actually "skip" a feedback (and this matches Chrome's behavior).
r.startSequenceNumber = &seq
+
return nil
}
- } else if !fb.addReceived(uint16(seq), arrivalTime) {
+ } else if !fb.addReceived(uint16(seq), arrivalTime) { //nolint:gosec // G115
// Could not add timestamp. Packet may be full. Return
// and try again with a fresh packet.
break
@@ -157,6 +161,7 @@ func (r *Recorder) maybeBuildFeedbackPacket(beginSeqNumInclusive, endSeqNumExclu
}
r.startSequenceNumber = &nextSequenceNumber
+
return fb
}
@@ -192,7 +197,7 @@ func (f *feedback) setBase(sequenceNumber uint16, timeUS int64) {
func (f *feedback) getRTCP() *rtcp.TransportLayerCC {
f.rtcp.PacketStatusCount = f.sequenceNumberCount
- f.rtcp.ReferenceTime = uint32(f.refTimestamp64MS)
+ f.rtcp.ReferenceTime = uint32(f.refTimestamp64MS) //nolint:gosec // G115
f.rtcp.BaseSequenceNumber = f.baseSequenceNumber
for len(f.lastChunk.deltas) > 0 {
f.chunks = append(f.chunks, f.lastChunk.encode())
@@ -200,7 +205,8 @@ func (f *feedback) getRTCP() *rtcp.TransportLayerCC {
f.rtcp.PacketChunks = append(f.rtcp.PacketChunks, f.chunks...)
f.rtcp.RecvDeltas = f.deltas
- padLen := 20 + len(f.rtcp.PacketChunks)*2 + f.len // 4 bytes header + 16 bytes twcc header + 2 bytes for each chunk + length of deltas
+ // 4 bytes header + 16 bytes twcc header + 2 bytes for each chunk + length of deltas
+ padLen := 20 + len(f.rtcp.PacketChunks)*2 + f.len
padding := padLen%4 != 0
for padLen%4 != 0 {
padLen++
@@ -209,7 +215,7 @@ func (f *feedback) getRTCP() *rtcp.TransportLayerCC {
Count: rtcp.FormatTCC,
Type: rtcp.TypeTransportSpecificFeedback,
Padding: padding,
- Length: uint16((padLen / 4) - 1),
+ Length: uint16((padLen / 4) - 1), //nolint:gosec // G115
}
return f.rtcp
@@ -223,7 +229,8 @@ func (f *feedback) addReceived(sequenceNumber uint16, timestampUS int64) bool {
} else {
delta250US = (deltaUS - rtcp.TypeTCCDeltaScaleFactor/2) / rtcp.TypeTCCDeltaScaleFactor
}
- if delta250US < math.MinInt16 || delta250US > math.MaxInt16 { // delta doesn't fit into 16 bit, need to create new packet
+ // delta doesn't fit into 16 bit, need to create new packet
+ if delta250US < math.MinInt16 || delta250US > math.MaxInt16 {
return false
}
deltaUSRounded := delta250US * rtcp.TypeTCCDeltaScaleFactor
@@ -257,6 +264,7 @@ func (f *feedback) addReceived(sequenceNumber uint16, timestampUS int64) bool {
f.lastTimestampUS += deltaUSRounded
f.sequenceNumberCount++
f.nextSequenceNumber++
+
return true
}
@@ -282,6 +290,7 @@ func (c *chunk) canAdd(delta uint16) bool {
if len(c.deltas) < maxRunLengthCap && !c.hasDifferentTypes && delta == c.deltas[0] {
return true
}
+
return false
}
@@ -294,13 +303,15 @@ func (c *chunk) add(delta uint16) {
func (c *chunk) encode() rtcp.PacketStatusChunk {
if !c.hasDifferentTypes {
defer c.reset()
+
return &rtcp.RunLengthChunk{
PacketStatusSymbol: c.deltas[0],
- RunLength: uint16(len(c.deltas)),
+ RunLength: uint16(len(c.deltas)), //nolint:gosec // G115
}
}
if len(c.deltas) == maxOneBitCap {
defer c.reset()
+
return &rtcp.StatusVectorChunk{
SymbolSize: rtcp.TypeTCCSymbolSizeOneBit,
SymbolList: c.deltas,
@@ -341,6 +352,7 @@ func maxInt(a, b int) int {
if a > b {
return a
}
+
return b
}
@@ -348,6 +360,7 @@ func minInt(a, b int) int {
if a < b {
return a
}
+
return b
}
@@ -355,6 +368,7 @@ func max64(a, b int64) int64 {
if a > b {
return a
}
+
return b
}
@@ -362,5 +376,6 @@ func min64(a, b int64) int64 {
if a < b {
return a
}
+
return b
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/registry.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/registry.go
index e36ef6bfb..9c1201426 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/registry.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/registry.go
@@ -13,7 +13,7 @@ func (r *Registry) Add(f Factory) {
r.factories = append(r.factories, f)
}
-// Build constructs a single Interceptor from a InterceptorRegistry
+// Build constructs a single Interceptor from a InterceptorRegistry.
func (r *Registry) Build(id string) (Interceptor, error) {
if len(r.factories) == 0 {
return &NoOp{}, nil
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/streaminfo.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/streaminfo.go
index cb261304f..d622312f3 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/streaminfo.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/interceptor/streaminfo.go
@@ -9,7 +9,7 @@ type RTPHeaderExtension struct {
ID int
}
-// StreamInfo is the Context passed when a StreamLocal or StreamRemote has been Binded or Unbinded
+// StreamInfo is the Context passed when a StreamLocal or StreamRemote has been Binded or Unbinded.
type StreamInfo struct {
ID string
Attributes Attributes
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/.golangci.yml
index 50211be0c..59edee274 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/.golangci.yml
@@ -19,12 +19,16 @@ linters-settings:
recommendations:
- errors
forbidigo:
+ analyze-types: true
forbid:
- ^fmt.Print(f|ln)?$
- ^log.(Panic|Fatal|Print)(f|ln)?$
- ^os.Exit$
- ^panic$
- ^print(ln)?$
+ - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$
+ pkg: ^testing$
+ msg: "use testify/assert instead"
varnamelen:
max-distance: 12
min-name-length: 2
@@ -37,6 +41,12 @@ linters-settings:
- w io.Writer
- r io.Reader
- b []byte
+ revive:
+ rules:
+ # Prefer 'any' type alias over 'interface{}' for Go 1.18+ compatibility
+ - name: use-any
+ severity: warning
+ disabled: false
linters:
enable:
@@ -59,7 +69,6 @@ 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
- gocognit # Computes and checks the cognitive complexity of functions
@@ -106,6 +115,7 @@ linters:
- 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
+ - funlen # Tool for detection of long functions
- 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.
@@ -127,9 +137,12 @@ issues:
exclude-dirs-use-default: false
exclude-rules:
# Allow complex tests and examples, better to be self contained
- - path: (examples|main\.go|_test\.go)
+ - path: (examples|main\.go)
linters:
+ - gocognit
- forbidigo
+ - path: _test\.go
+ linters:
- gocognit
# Allow forbidden identifiers in CLI commands
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/README.md
index b9824abb6..20ae88948 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/README.md
@@ -6,7 +6,7 @@
The Pion logging library
-
+
@@ -20,9 +20,9 @@
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Slack](https://pion.ly/slack).
+Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt).
-Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
+Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/logger.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/logger.go
index eb1e56af6..b23aaa144 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/logger.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/logger.go
@@ -93,7 +93,7 @@ func (ll *DefaultLeveledLogger) WithOutput(output io.Writer) *DefaultLeveledLogg
return ll
}
-func (ll *DefaultLeveledLogger) logf(logger *log.Logger, level LogLevel, format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) logf(logger *log.Logger, level LogLevel, format string, args ...any) {
if ll.level.Get() < level {
return
}
@@ -116,7 +116,7 @@ func (ll *DefaultLeveledLogger) Trace(msg string) {
}
// Tracef formats and emits a message if the logger is at or below LogLevelTrace.
-func (ll *DefaultLeveledLogger) Tracef(format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) Tracef(format string, args ...any) {
ll.logf(ll.trace, LogLevelTrace, format, args...)
}
@@ -126,7 +126,7 @@ func (ll *DefaultLeveledLogger) Debug(msg string) {
}
// Debugf formats and emits a message if the logger is at or below LogLevelDebug.
-func (ll *DefaultLeveledLogger) Debugf(format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) Debugf(format string, args ...any) {
ll.logf(ll.debug, LogLevelDebug, format, args...)
}
@@ -136,7 +136,7 @@ func (ll *DefaultLeveledLogger) Info(msg string) {
}
// Infof formats and emits a message if the logger is at or below LogLevelInfo.
-func (ll *DefaultLeveledLogger) Infof(format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) Infof(format string, args ...any) {
ll.logf(ll.info, LogLevelInfo, format, args...)
}
@@ -146,7 +146,7 @@ func (ll *DefaultLeveledLogger) Warn(msg string) {
}
// Warnf formats and emits a message if the logger is at or below LogLevelWarn.
-func (ll *DefaultLeveledLogger) Warnf(format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) Warnf(format string, args ...any) {
ll.logf(ll.warn, LogLevelWarn, format, args...)
}
@@ -156,7 +156,7 @@ func (ll *DefaultLeveledLogger) Error(msg string) {
}
// Errorf formats and emits a message if the logger is at or below LogLevelError.
-func (ll *DefaultLeveledLogger) Errorf(format string, args ...interface{}) {
+func (ll *DefaultLeveledLogger) Errorf(format string, args ...any) {
ll.logf(ll.err, LogLevelError, format, args...)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/scoped.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/scoped.go
index 7b3a550ee..aac518eb5 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/scoped.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/logging/scoped.go
@@ -58,15 +58,15 @@ const (
// LeveledLogger is the basic pion Logger interface.
type LeveledLogger interface {
Trace(msg string)
- Tracef(format string, args ...interface{})
+ Tracef(format string, args ...any)
Debug(msg string)
- Debugf(format string, args ...interface{})
+ Debugf(format string, args ...any)
Info(msg string)
- Infof(format string, args ...interface{})
+ Infof(format string, args ...any)
Warn(msg string)
- Warnf(format string, args ...interface{})
+ Warnf(format string, args ...any)
Error(msg string)
- Errorf(format string, args ...interface{})
+ Errorf(format string, args ...any)
}
// LoggerFactory is the basic pion LoggerFactory interface.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/.golangci.yml
index 120faf29b..59edee274 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/.golangci.yml
@@ -41,6 +41,12 @@ linters-settings:
- w io.Writer
- r io.Reader
- b []byte
+ revive:
+ rules:
+ # Prefer 'any' type alias over 'interface{}' for Go 1.18+ compatibility
+ - name: use-any
+ severity: warning
+ disabled: false
linters:
enable:
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/codecs/h265_packet.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/codecs/h265_packet.go
index ff24f080f..953b3c97c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/codecs/h265_packet.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/codecs/h265_packet.go
@@ -15,8 +15,9 @@ import (
//
var (
- errH265CorruptedPacket = errors.New("corrupted h265 packet")
- errInvalidH265PacketType = errors.New("invalid h265 packet type")
+ errH265CorruptedPacket = errors.New("corrupted h265 packet")
+ errInvalidH265PacketType = errors.New("invalid h265 packet type")
+ errExpectFragmentationStartUnit = errors.New("expecting a fragmentation start unit")
)
//
@@ -192,6 +193,15 @@ func (p *H265SingleNALUnitPacket) Payload() []byte {
func (p *H265SingleNALUnitPacket) isH265Packet() {}
+func (p *H265SingleNALUnitPacket) doPackaging(buf []byte) []byte {
+ buf = append(buf, annexbNALUStartCode...)
+ buf = append(buf, byte(p.payloadHeader>>8), byte(p.payloadHeader&0xFF))
+
+ buf = append(buf, p.payload...)
+
+ return buf
+}
+
//
// Aggregation Packets implementation
//
@@ -399,6 +409,21 @@ func (p *H265AggregationPacket) OtherUnits() []H265AggregationUnit {
func (p *H265AggregationPacket) isH265Packet() {}
+func (p *H265AggregationPacket) doPackaging(buf []byte) []byte {
+ if p.firstUnit == nil {
+ return buf
+ }
+ buf = append(buf, annexbNALUStartCode...)
+ buf = append(buf, p.firstUnit.nalUnit...)
+
+ for _, unit := range p.otherUnits {
+ buf = append(buf, annexbNALUStartCode...)
+ buf = append(buf, unit.nalUnit...)
+ }
+
+ return buf
+}
+
//
// Fragmentation Unit implementation
//
@@ -536,6 +561,64 @@ func (p *H265FragmentationUnitPacket) Payload() []byte {
func (p *H265FragmentationUnitPacket) isH265Packet() {}
+// H265FragmentationPacket represents a Fragmentation packet, which contains one or more Fragmentation Units.
+type H265FragmentationPacket struct {
+ payloadHeader H265NALUHeader
+ donl *uint16
+ units []*H265FragmentationUnitPacket
+ payload []byte
+}
+
+func NewH265FragmentationPacket(startUnit *H265FragmentationUnitPacket) *H265FragmentationPacket {
+ return &H265FragmentationPacket{
+ payloadHeader: (startUnit.payloadHeader & 0x81FF) | (H265NALUHeader(startUnit.FuHeader().FuType()) << 9),
+ donl: startUnit.donl,
+ units: []*H265FragmentationUnitPacket{startUnit},
+ }
+}
+
+// PayloadHeader returns the NALU header of the packet.
+func (p *H265FragmentationPacket) PayloadHeader() H265NALUHeader {
+ return p.payloadHeader
+}
+
+// DONL returns the DONL of the packet.
+func (p *H265FragmentationPacket) DONL() *uint16 {
+ return p.donl
+}
+
+// Payload returns the Fragmentation packet payload.
+func (p *H265FragmentationPacket) Payload() []byte {
+ return p.payload
+}
+
+func (p *H265FragmentationPacket) isH265Packet() {}
+
+func (p *H265FragmentationPacket) doPackaging(buf []byte) []byte {
+ if len(p.payload) == 0 {
+ return buf
+ }
+
+ buf = append(buf, annexbNALUStartCode...)
+ buf = append(buf, byte(p.payloadHeader>>8), byte(p.payloadHeader&0xFF))
+ buf = append(buf, p.payload...)
+
+ return buf
+}
+
+func (p *H265FragmentationPacket) appendUnit(unit *H265FragmentationUnitPacket) {
+ if len(p.payload) > 0 {
+ // already have end unit
+ return
+ }
+ p.units = append(p.units, unit)
+ if unit.FuHeader().E() {
+ for _, u := range p.units {
+ p.payload = append(p.payload, u.payload...)
+ }
+ }
+}
+
//
// PACI implementation
//
@@ -691,6 +774,21 @@ func (p *H265PACIPacket) Unmarshal(payload []byte) ([]byte, error) {
func (p *H265PACIPacket) isH265Packet() {}
+func (p *H265PACIPacket) doPackaging(buf []byte) []byte {
+ buf = append(buf, annexbNALUStartCode...)
+ buf = append(buf, byte(p.payloadHeader>>8), byte(p.payloadHeader&0xFF))
+
+ buf = binary.BigEndian.AppendUint16(buf, p.paciHeaderFields)
+
+ if len(p.phes) > 0 {
+ buf = append(buf, p.phes...)
+ }
+
+ buf = append(buf, p.payload...)
+
+ return buf
+}
+
//
// Temporal Scalability Control Information
//
@@ -745,10 +843,11 @@ func (h H265TSCI) RES() uint8 {
type isH265Packet interface {
isH265Packet()
+ doPackaging([]byte) []byte
}
var (
- _ isH265Packet = (*H265FragmentationUnitPacket)(nil)
+ _ isH265Packet = (*H265FragmentationPacket)(nil)
_ isH265Packet = (*H265PACIPacket)(nil)
_ isH265Packet = (*H265SingleNALUnitPacket)(nil)
_ isH265Packet = (*H265AggregationPacket)(nil)
@@ -802,7 +901,15 @@ func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) { // nolint:cyclo
return nil, err
}
- p.packet = decoded
+ if decoded.FuHeader().S() {
+ p.packet = NewH265FragmentationPacket(decoded)
+ } else {
+ if fu, ok := p.packet.(*H265FragmentationPacket); !ok {
+ return nil, errExpectFragmentationStartUnit
+ } else {
+ fu.appendUnit(decoded)
+ }
+ }
case payloadHeader.IsAggregationPacket():
decoded := &H265AggregationPacket{}
@@ -825,7 +932,7 @@ func (p *H265Packet) Unmarshal(payload []byte) ([]byte, error) { // nolint:cyclo
p.packet = decoded
}
- return nil, nil
+ return p.packet.doPackaging(nil), nil
}
// Packet returns the populated packet.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/header_extension.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/header_extension.go
index b36d09af8..5e01998cf 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/header_extension.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/header_extension.go
@@ -10,9 +10,7 @@ import (
)
const (
- headerExtensionProfileOneByte = 0xBEDE
- headerExtensionProfileTwoByte = 0x1000
- headerExtensionIDReserved = 0xF
+ headerExtensionIDReserved = 0xF
)
// HeaderExtension represents an RTP extension header.
@@ -140,7 +138,7 @@ func (e *OneByteHeaderExtension) Del(id uint8) error {
// Unmarshal parses the extension payload.
func (e *OneByteHeaderExtension) Unmarshal(buf []byte) (int, error) {
profile := binary.BigEndian.Uint16(buf[0:2])
- if profile != headerExtensionProfileOneByte {
+ if profile != ExtensionProfileOneByte {
return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2])
}
e.payload = buf
@@ -283,7 +281,7 @@ func (e *TwoByteHeaderExtension) Del(id uint8) error {
// Unmarshal parses the extension payload.
func (e *TwoByteHeaderExtension) Unmarshal(buf []byte) (int, error) {
profile := binary.BigEndian.Uint16(buf[0:2])
- if profile != headerExtensionProfileTwoByte {
+ if profile != ExtensionProfileTwoByte {
return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2])
}
e.payload = buf
@@ -354,7 +352,7 @@ func (e *RawExtension) Del(id uint8) error {
// Unmarshal parses the extension from the given buffer.
func (e *RawExtension) Unmarshal(buf []byte) (int, error) {
profile := binary.BigEndian.Uint16(buf[0:2])
- if profile == headerExtensionProfileOneByte || profile == headerExtensionProfileTwoByte {
+ if profile == ExtensionProfileOneByte || profile == ExtensionProfileTwoByte {
return 0, fmt.Errorf("%w actual(%x)", errHeaderExtensionNotFound, buf[0:2])
}
e.payload = buf
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packet.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packet.go
index c51d8c7d8..b0166730d 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packet.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packet.go
@@ -29,6 +29,10 @@ type Header struct {
ExtensionProfile uint16
Extensions []Extension
+ // PaddingLength is the length of the padding in bytes. It is not part of the RTP header
+ // (it is sent in the last byte of RTP packet padding), but logically it belongs here.
+ PaddingSize byte
+
// Deprecated: will be removed in a future version.
PayloadOffset int
}
@@ -36,36 +40,50 @@ type Header struct {
// Packet represents an RTP Packet.
type Packet struct {
Header
- Payload []byte
- PaddingSize byte
+ Payload []byte
+
+ PaddingSize byte // Deprecated: will be removed in a future version. Use Header.PaddingSize instead.
// Deprecated: will be removed in a future version.
Raw []byte
+
+ // Please do not add any new field directly to Packet struct unless you know that it is safe.
+ // pion internally passes Header and Payload separately, what causes bugs like
+ // https://github.com/pion/webrtc/issues/2403 .
}
const (
- headerLength = 4
- versionShift = 6
- versionMask = 0x3
- paddingShift = 5
- paddingMask = 0x1
- extensionShift = 4
- extensionMask = 0x1
- extensionProfileOneByte = 0xBEDE
- extensionProfileTwoByte = 0x1000
- extensionIDReserved = 0xF
- ccMask = 0xF
- markerShift = 7
- markerMask = 0x1
- ptMask = 0x7F
- seqNumOffset = 2
- seqNumLength = 2
- timestampOffset = 4
- timestampLength = 4
- ssrcOffset = 8
- ssrcLength = 4
- csrcOffset = 12
- csrcLength = 4
+ // ExtensionProfileOneByte is the RTP One Byte Header Extension Profile, defined in RFC 8285.
+ ExtensionProfileOneByte = 0xBEDE
+ // ExtensionProfileTwoByte is the RTP Two Byte Header Extension Profile, defined in RFC 8285.
+ ExtensionProfileTwoByte = 0x1000
+ // CryptexProfileOneByte is the Cryptex One Byte Header Extension Profile, defined in RFC 9335.
+ CryptexProfileOneByte = 0xC0DE
+ // CryptexProfileTwoByte is the Cryptex Two Byte Header Extension Profile, defined in RFC 9335.
+ CryptexProfileTwoByte = 0xC2DE
+)
+
+const (
+ headerLength = 4
+ versionShift = 6
+ versionMask = 0x3
+ paddingShift = 5
+ paddingMask = 0x1
+ extensionShift = 4
+ extensionMask = 0x1
+ extensionIDReserved = 0xF
+ ccMask = 0xF
+ markerShift = 7
+ markerMask = 0x1
+ ptMask = 0x7F
+ seqNumOffset = 2
+ seqNumLength = 2
+ timestampOffset = 4
+ timestampLength = 4
+ ssrcOffset = 8
+ ssrcLength = 4
+ csrcOffset = 12
+ csrcLength = 4
)
// String helps with debugging by printing packet information in a readable way.
@@ -155,7 +173,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
return n, fmt.Errorf("size %d < %d: %w", len(buf), extensionEnd, errHeaderSizeInsufficientForExtension)
}
- if h.ExtensionProfile == extensionProfileOneByte || h.ExtensionProfile == extensionProfileTwoByte {
+ if h.ExtensionProfile == ExtensionProfileOneByte || h.ExtensionProfile == ExtensionProfileTwoByte {
var (
extid uint8
payloadLen int
@@ -168,7 +186,7 @@ func (h *Header) Unmarshal(buf []byte) (n int, err error) { //nolint:gocognit,cy
continue
}
- if h.ExtensionProfile == extensionProfileOneByte {
+ if h.ExtensionProfile == ExtensionProfileOneByte {
extid = buf[n] >> 4
payloadLen = int(buf[n]&^0xF0 + 1)
n++
@@ -219,11 +237,12 @@ func (p *Packet) Unmarshal(buf []byte) error {
if end <= n {
return errTooSmall
}
- p.PaddingSize = buf[end-1]
- end -= int(p.PaddingSize)
+ p.Header.PaddingSize = buf[end-1]
+ end -= int(p.Header.PaddingSize)
} else {
- p.PaddingSize = 0
+ p.Header.PaddingSize = 0
}
+ p.PaddingSize = p.Header.PaddingSize
if end < n {
return errTooSmall
}
@@ -302,14 +321,14 @@ func (h Header) MarshalTo(buf []byte) (n int, err error) { //nolint:cyclop
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
- case extensionProfileOneByte:
+ case ExtensionProfileOneByte:
for _, extension := range h.Extensions {
buf[n] = extension.id<<4 | (uint8(len(extension.payload)) - 1) // nolint: gosec // G115
n++
n += copy(buf[n:], extension.payload)
}
// RFC 8285 RTP Two Byte Header Extension
- case extensionProfileTwoByte:
+ case ExtensionProfileTwoByte:
for _, extension := range h.Extensions {
buf[n] = extension.id
n++
@@ -353,12 +372,12 @@ func (h Header) MarshalSize() int {
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
- case extensionProfileOneByte:
+ case ExtensionProfileOneByte:
for _, extension := range h.Extensions {
extSize += 1 + len(extension.payload)
}
// RFC 8285 RTP Two Byte Header Extension
- case extensionProfileTwoByte:
+ case ExtensionProfileTwoByte:
for _, extension := range h.Extensions {
extSize += 2 + len(extension.payload)
}
@@ -378,7 +397,7 @@ func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocogni
if h.Extension { // nolint: nestif
switch h.ExtensionProfile {
// RFC 8285 RTP One Byte Header Extension
- case extensionProfileOneByte:
+ case ExtensionProfileOneByte:
if id < 1 || id > 14 {
return fmt.Errorf("%w actual(%d)", errRFC8285OneByteHeaderIDRange, id)
}
@@ -386,7 +405,7 @@ func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocogni
return fmt.Errorf("%w actual(%d)", errRFC8285OneByteHeaderSize, len(payload))
}
// RFC 8285 RTP Two Byte Header Extension
- case extensionProfileTwoByte:
+ case ExtensionProfileTwoByte:
if id < 1 {
return fmt.Errorf("%w actual(%d)", errRFC8285TwoByteHeaderIDRange, id)
}
@@ -418,9 +437,9 @@ func (h *Header) SetExtension(id uint8, payload []byte) error { //nolint:gocogni
switch payloadLen := len(payload); {
case payloadLen <= 16:
- h.ExtensionProfile = extensionProfileOneByte
+ h.ExtensionProfile = ExtensionProfileOneByte
case payloadLen > 16 && payloadLen < 256:
- h.ExtensionProfile = extensionProfileTwoByte
+ h.ExtensionProfile = ExtensionProfileTwoByte
}
h.Extensions = append(h.Extensions, Extension{id: id, payload: payload})
@@ -490,7 +509,7 @@ func (p Packet) Marshal() (buf []byte, err error) {
// MarshalTo serializes the packet and writes to the buffer.
func (p *Packet) MarshalTo(buf []byte) (n int, err error) {
- if p.Header.Padding && p.PaddingSize == 0 {
+ if p.Header.Padding && p.paddingSize() == 0 {
return 0, errInvalidRTPPadding
}
@@ -499,23 +518,28 @@ func (p *Packet) MarshalTo(buf []byte) (n int, err error) {
return 0, err
}
+ return marshalPayloadAndPaddingTo(buf, n, &p.Header, p.Payload, p.paddingSize())
+}
+
+func marshalPayloadAndPaddingTo(buf []byte, offset int, header *Header, payload []byte, paddingSize byte,
+) (n int, err error) {
// Make sure the buffer is large enough to hold the packet.
- if n+len(p.Payload)+int(p.PaddingSize) > len(buf) {
+ if offset+len(payload)+int(paddingSize) > len(buf) {
return 0, io.ErrShortBuffer
}
- m := copy(buf[n:], p.Payload)
+ m := copy(buf[offset:], payload)
- if p.Header.Padding {
- buf[n+m+int(p.PaddingSize-1)] = p.PaddingSize
+ if header.Padding {
+ buf[offset+m+int(paddingSize-1)] = paddingSize
}
- return n + m + int(p.PaddingSize), nil
+ return offset + m + int(paddingSize), nil
}
// MarshalSize returns the size of the packet once marshaled.
func (p Packet) MarshalSize() int {
- return p.Header.MarshalSize() + len(p.Payload) + int(p.PaddingSize)
+ return p.Header.MarshalSize() + len(p.Payload) + int(p.paddingSize())
}
// Clone returns a deep copy of p.
@@ -552,3 +576,45 @@ func (h Header) Clone() Header {
return clone
}
+
+func (p *Packet) paddingSize() byte {
+ if p.Header.PaddingSize > 0 {
+ return p.Header.PaddingSize
+ }
+
+ return p.PaddingSize
+}
+
+// MarshalPacketTo serializes the header and payload into bytes.
+// Parts of pion code passes RTP header and payload separately, so this function
+// is provided to help with that.
+//
+// Deprecated: this function is a temporary workaround and will be removed in pion/webrtc v5.
+func MarshalPacketTo(buf []byte, header *Header, payload []byte) (int, error) {
+ n, err := header.MarshalTo(buf)
+ if err != nil {
+ return 0, err
+ }
+
+ return marshalPayloadAndPaddingTo(buf, n, header, payload, header.PaddingSize)
+}
+
+// PacketMarshalSize returns the size of the header and payload once marshaled.
+// Parts of pion code passes RTP header and payload separately, so this function
+// is provided to help with that.
+//
+// Deprecated: this function is a temporary workaround and will be removed in pion/webrtc v5.
+func PacketMarshalSize(header *Header, payload []byte) int {
+ return header.MarshalSize() + len(payload) + int(header.PaddingSize)
+}
+
+// HeaderAndPacketMarshalSize returns the size of the header and full packet once marshaled.
+// Parts of pion code passes RTP header and payload separately, so this function
+// is provided to help with that.
+//
+// Deprecated: this function is a temporary workaround and will be removed in pion/webrtc v5.
+func HeaderAndPacketMarshalSize(header *Header, payload []byte) (headerSize int, packetSize int) {
+ headerSize = header.MarshalSize()
+
+ return headerSize, headerSize + len(payload) + int(header.PaddingSize)
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packetizer.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packetizer.go
index c0dbea49f..181d0d2f1 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packetizer.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/rtp/packetizer.go
@@ -165,9 +165,6 @@ func (p *packetizer) GeneratePadding(samples uint32) []*Packet {
packets := make([]*Packet, samples)
for i := 0; i < int(samples); i++ {
- pp := make([]byte, 255)
- pp[254] = 255
-
packets[i] = &Packet{
Header: Header{
Version: 2,
@@ -179,8 +176,8 @@ func (p *packetizer) GeneratePadding(samples uint32) []*Packet {
Timestamp: p.Timestamp, // Use latest timestamp
SSRC: p.SSRC,
CSRC: []uint32{},
+ PaddingSize: 255,
},
- Payload: pp,
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/.golangci.yml
index 88cb4fbf9..120faf29b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/.golangci.yml
@@ -19,12 +19,16 @@ linters-settings:
recommendations:
- errors
forbidigo:
+ analyze-types: true
forbid:
- ^fmt.Print(f|ln)?$
- ^log.(Panic|Fatal|Print)(f|ln)?$
- ^os.Exit$
- ^panic$
- ^print(ln)?$
+ - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$
+ pkg: ^testing$
+ msg: "use testify/assert instead"
varnamelen:
max-distance: 12
min-name-length: 2
@@ -127,9 +131,12 @@ issues:
exclude-dirs-use-default: false
exclude-rules:
# Allow complex tests and examples, better to be self contained
- - path: (examples|main\.go|_test\.go)
+ - path: (examples|main\.go)
linters:
+ - gocognit
- forbidigo
+ - path: _test\.go
+ linters:
- gocognit
# Allow forbidden identifiers in CLI commands
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/README.md
index 1cb8dbd21..32fa30dd7 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/README.md
@@ -7,10 +7,10 @@
-
+
-
+
@@ -21,9 +21,9 @@
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Slack](https://pion.ly/slack).
+Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt).
-Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
+Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
@@ -32,4 +32,4 @@ If you need commercial support or don't want to use public methods you can conta
Check out the [contributing wiki](https://github.com/pion/webrtc/wiki/Contributing) to join the group of amazing people making this project possible
### License
-MIT License - see [LICENSE](LICENSE) for full text
\ No newline at end of file
+MIT License - see [LICENSE](LICENSE) for full text
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/jsep.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/jsep.go
index 388a13e9e..ce0ba53ab 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/jsep.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/jsep.go
@@ -23,6 +23,7 @@ const (
AttrKeyConnectionSetup = "setup"
AttrKeyMID = "mid"
AttrKeyICELite = "ice-lite"
+ AttrKeyICEOptions = "ice-options"
AttrKeyRTCPMux = "rtcp-mux"
AttrKeyRTCPRsize = "rtcp-rsize"
AttrKeyInactive = "inactive"
@@ -31,6 +32,7 @@ const (
AttrKeySendRecv = "sendrecv"
AttrKeyExtMap = "extmap"
AttrKeyExtMapAllowMixed = "extmap-allow-mixed"
+ AttrKeyCryptex = "cryptex"
)
// Constants for semantic tokens used in JSEP.
@@ -38,7 +40,9 @@ const (
SemanticTokenLipSynchronization = "LS"
SemanticTokenFlowIdentification = "FID"
SemanticTokenForwardErrorCorrection = "FEC"
- SemanticTokenWebRTCMediaStreams = "WMS"
+ // https://datatracker.ietf.org/doc/html/rfc5956#section-4.1
+ SemanticTokenForwardErrorCorrectionFramework = "FEC-FR"
+ SemanticTokenWebRTCMediaStreams = "WMS"
)
// Constants for extmap key.
@@ -113,6 +117,12 @@ func (s *SessionDescription) WithValueAttribute(key, value string) *SessionDescr
return s
}
+// WithICETrickleAdvertised advertises ICE trickle support in the session description.
+// See https://datatracker.ietf.org/doc/html/rfc9429#section-5.2.1
+func (s *SessionDescription) WithICETrickleAdvertised() *SessionDescription {
+ return s.WithValueAttribute(AttrKeyICEOptions, "trickle")
+}
+
// WithFingerprint adds a fingerprint to the session description.
func (s *SessionDescription) WithFingerprint(algorithm, value string) *SessionDescription {
return s.WithValueAttribute("fingerprint", algorithm+" "+value)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/unmarshal.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/unmarshal.go
index e884b0f9f..8ef01e15c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/unmarshal.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/unmarshal.go
@@ -986,10 +986,10 @@ func timeShorthand(b byte) int64 {
func parsePort(value string) (int, error) {
port, err := strconv.Atoi(value)
if err != nil {
- return 0, fmt.Errorf("%w `%v`", errSDPInvalidPortValue, port)
+ return 0, fmt.Errorf("%w `%v`", errSDPInvalidPortValue, value)
}
- if port < 0 || port > 65536 {
+ if port < 0 || port > 65535 {
return 0, fmt.Errorf("%w -- out of range `%v`", errSDPInvalidPortValue, port)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/util.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/util.go
index 4550feece..7cf17a961 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/util.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/sdp/v3/util.go
@@ -19,16 +19,12 @@ const (
)
var (
- errExtractCodecRtpmap = errors.New("could not extract codec from rtpmap")
- errExtractCodecFmtp = errors.New("could not extract codec from fmtp")
- errExtractCodecRtcpFb = errors.New("could not extract codec from rtcp-fb")
- errMultipleName = errors.New("codec has multiple names defined")
- errMultipleClockRate = errors.New("codec has multiple clock rates")
- errMultipleEncodingParameters = errors.New("codec has multiple encoding parameters")
- errMultipleFmtp = errors.New("codec has multiple fmtp values")
- errPayloadTypeNotFound = errors.New("payload type not found")
- errCodecNotFound = errors.New("codec not found")
- errSyntaxError = errors.New("SyntaxError")
+ errExtractCodecRtpmap = errors.New("could not extract codec from rtpmap")
+ errExtractCodecFmtp = errors.New("could not extract codec from fmtp")
+ errExtractCodecRtcpFb = errors.New("could not extract codec from rtcp-fb")
+ errPayloadTypeNotFound = errors.New("payload type not found")
+ errCodecNotFound = errors.New("codec not found")
+ errSyntaxError = errors.New("SyntaxError")
)
// ConnectionRole indicates which of the end points should initiate the connection establishment.
@@ -207,49 +203,30 @@ func parseRtcpFb(rtcpFb string) (codec Codec, isWildcard bool, err error) {
return codec, isWildcard, nil
}
-func mergeCodecs(codec Codec, codecs map[uint8]Codec) error { // nolint: cyclop
+func mergeCodecs(codec Codec, codecs map[uint8]Codec) {
savedCodec := codecs[codec.PayloadType]
- savedCodec.PayloadType = codec.PayloadType
-
- if codec.Name != "" {
- if savedCodec.Name != "" && savedCodec.Name != codec.Name {
- return errMultipleName
- }
+ if savedCodec.PayloadType == 0 {
+ savedCodec.PayloadType = codec.PayloadType
+ }
+ if savedCodec.Name == "" {
savedCodec.Name = codec.Name
}
-
- if codec.ClockRate != 0 {
- if savedCodec.ClockRate != 0 && savedCodec.ClockRate != codec.ClockRate {
- return errMultipleClockRate
- }
-
+ if savedCodec.ClockRate == 0 {
savedCodec.ClockRate = codec.ClockRate
}
-
- if codec.EncodingParameters != "" {
- if savedCodec.EncodingParameters != "" && savedCodec.EncodingParameters != codec.EncodingParameters {
- return errMultipleEncodingParameters
- }
-
+ if savedCodec.EncodingParameters == "" {
savedCodec.EncodingParameters = codec.EncodingParameters
}
-
- if codec.Fmtp != "" {
- if savedCodec.Fmtp != "" && savedCodec.Fmtp != codec.Fmtp {
- return errMultipleFmtp
- }
-
+ if savedCodec.Fmtp == "" {
savedCodec.Fmtp = codec.Fmtp
}
-
savedCodec.RTCPFeedback = append(savedCodec.RTCPFeedback, codec.RTCPFeedback...)
- codecs[savedCodec.PayloadType] = savedCodec
- return nil
+ codecs[savedCodec.PayloadType] = savedCodec
}
-func (s *SessionDescription) buildCodecMap() (map[uint8]Codec, error) { //nolint:cyclop, gocognit
+func (s *SessionDescription) buildCodecMap() map[uint8]Codec { //nolint:cyclop
codecs := map[uint8]Codec{
// static codecs that do not require a rtpmap
0: {
@@ -272,16 +249,12 @@ func (s *SessionDescription) buildCodecMap() (map[uint8]Codec, error) { //nolint
case strings.HasPrefix(attr, "rtpmap:"):
codec, err := parseRtpmap(attr)
if err == nil {
- if err = mergeCodecs(codec, codecs); err != nil {
- return nil, err
- }
+ mergeCodecs(codec, codecs)
}
case strings.HasPrefix(attr, "fmtp:"):
codec, err := parseFmtp(attr)
if err == nil {
- if err = mergeCodecs(codec, codecs); err != nil {
- return nil, err
- }
+ mergeCodecs(codec, codecs)
}
case strings.HasPrefix(attr, "rtcp-fb:"):
codec, isWildcard, err := parseRtcpFb(attr)
@@ -290,9 +263,7 @@ func (s *SessionDescription) buildCodecMap() (map[uint8]Codec, error) { //nolint
case isWildcard:
wildcardRTCPFeedback = append(wildcardRTCPFeedback, codec.RTCPFeedback...)
default:
- if err = mergeCodecs(codec, codecs); err != nil {
- return nil, err
- }
+ mergeCodecs(codec, codecs)
}
}
}
@@ -306,7 +277,7 @@ func (s *SessionDescription) buildCodecMap() (map[uint8]Codec, error) { //nolint
codecs[i] = codec
}
- return codecs, nil
+ return codecs
}
func equivalentFmtp(want, got string) bool {
@@ -350,10 +321,7 @@ func codecsMatch(wanted, got Codec) bool {
// GetCodecForPayloadType scans the SessionDescription for the given payload type and returns the codec.
func (s *SessionDescription) GetCodecForPayloadType(payloadType uint8) (Codec, error) {
- codecs, err := s.buildCodecMap()
- if err != nil {
- return Codec{}, err
- }
+ codecs := s.buildCodecMap()
codec, ok := codecs[payloadType]
if ok {
@@ -366,10 +334,7 @@ func (s *SessionDescription) GetCodecForPayloadType(payloadType uint8) (Codec, e
// GetPayloadTypeForCodec scans the SessionDescription for a codec that matches the provided codec
// as closely as possible and returns its payload type.
func (s *SessionDescription) GetPayloadTypeForCodec(wanted Codec) (uint8, error) {
- codecs, err := s.buildCodecMap()
- if err != nil {
- return 0, err
- }
+ codecs := s.buildCodecMap()
for payloadType, codec := range codecs {
if codecsMatch(wanted, codec) {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/.golangci.yml
index a3235bec2..120faf29b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/.golangci.yml
@@ -19,23 +19,42 @@ linters-settings:
recommendations:
- errors
forbidigo:
+ analyze-types: true
forbid:
- ^fmt.Print(f|ln)?$
- ^log.(Panic|Fatal|Print)(f|ln)?$
- ^os.Exit$
- ^panic$
- ^print(ln)?$
+ - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$
+ pkg: ^testing$
+ msg: "use testify/assert instead"
+ 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`.
@@ -46,18 +65,17 @@ linters:
- forcetypeassert # finds forced type assertions
- 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 +83,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 +99,22 @@ 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 +122,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!
@@ -114,9 +131,12 @@ issues:
exclude-dirs-use-default: false
exclude-rules:
# Allow complex tests and examples, better to be self contained
- - path: (examples|main\.go|_test\.go)
+ - path: (examples|main\.go)
linters:
+ - gocognit
- forbidigo
+ - path: _test\.go
+ linters:
- gocognit
# Allow forbidden identifiers in CLI commands
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/README.md
index d6fdbd0d3..10ede23cd 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/README.md
@@ -7,7 +7,7 @@
-
+
@@ -21,9 +21,9 @@
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Slack](https://pion.ly/slack).
+Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt).
-Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
+Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/context.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/context.go
index cb2ed56a7..3bced572a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/context.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/context.go
@@ -24,11 +24,9 @@ const (
seqNumMedian = 1 << 15
seqNumMax = 1 << 16
-
- srtcpIndexSize = 4
)
-// Encrypt/Decrypt state for a single SRTP SSRC
+// Encrypt/Decrypt state for a single SRTP SSRC.
type srtpSSRCState struct {
ssrc uint32
rolloverHasProcessed bool
@@ -36,13 +34,30 @@ type srtpSSRCState struct {
replayDetector replaydetector.ReplayDetector
}
-// Encrypt/Decrypt state for a single SRTCP SSRC
+// Encrypt/Decrypt state for a single SRTCP SSRC.
type srtcpSSRCState struct {
srtcpIndex uint32
ssrc uint32
replayDetector replaydetector.ReplayDetector
}
+// RCCMode is the mode of Roll-over Counter Carrying Transform from RFC 4771.
+type RCCMode int
+
+const (
+ // RCCModeNone is the default mode.
+ RCCModeNone RCCMode = iota
+ // RCCMode1 is RCCm1 mode from RFC 4771. In this mode ROC and truncated auth tag is sent every R-th packet,
+ // and no auth tag in other ones. This mode is not supported by pion/srtp.
+ RCCMode1
+ // RCCMode2 is RCCm2 mode from RFC 4771. In this mode ROC and truncated auth tag is sent every R-th packet,
+ // and full auth tag in other ones. This mode is supported for AES-CM and NULL profiles only.
+ RCCMode2
+ // RCCMode3 is RCCm3 mode from RFC 4771. In this mode ROC is sent every R-th packet (without truncated auth tag),
+ // and no auth tag in other ones. This mode is supported for AES-GCM profiles only.
+ RCCMode3
+)
+
// Context represents a SRTP cryptographic context.
// Context can only be used for one-way operations.
// it must either used ONLY for encryption or ONLY for decryption.
@@ -60,11 +75,18 @@ type Context struct {
profile ProtectionProfile
- sendMKI []byte // Master Key Identifier used for encrypting RTP/RTCP packets. Set to nil if MKI is not enabled.
- mkis map[string]srtpCipher // Master Key Identifier to cipher mapping. Used for decrypting packets. Empty if MKI is not enabled.
+ // Master Key Identifier used for encrypting RTP/RTCP packets. Set to nil if MKI is not enabled.
+ sendMKI []byte
+ // Master Key Identifier to cipher mapping. Used for decrypting packets. Empty if MKI is not enabled.
+ mkis map[string]srtpCipher
encryptSRTP bool
encryptSRTCP bool
+
+ rccMode RCCMode
+ rocTransmitRate uint16
+
+ authTagRTPLen *int
}
// CreateContext creates a new SRTP Context.
@@ -74,7 +96,11 @@ type Context struct {
// Following example create SRTP Context with replay protection with window size of 256.
//
// decCtx, err := srtp.CreateContext(key, salt, profile, srtp.SRTPReplayProtection(256))
-func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts ...ContextOption) (c *Context, err error) {
+func CreateContext(
+ masterKey, masterSalt []byte,
+ profile ProtectionProfile,
+ opts ...ContextOption,
+) (c *Context, err error) {
c = &Context{
srtpSSRCStates: map[uint32]*srtpSSRCState{},
srtcpSSRCStates: map[uint32]*srtcpSSRCState{},
@@ -96,6 +122,21 @@ func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts
}
}
+ if err = c.checkRCCMode(); err != nil {
+ return nil, err
+ }
+
+ if c.authTagRTPLen != nil {
+ var authKeyLen int
+ authKeyLen, err = c.profile.AuthKeyLen()
+ if err != nil {
+ return nil, err
+ }
+ if *c.authTagRTPLen > authKeyLen {
+ return nil, errTooLongSRTPAuthTag
+ }
+ }
+
c.cipher, err = c.createCipher(c.sendMKI, masterKey, masterSalt, c.encryptSRTP, c.encryptSRTCP)
if err != nil {
return nil, err
@@ -107,7 +148,8 @@ func CreateContext(masterKey, masterSalt []byte, profile ProtectionProfile, opts
return c, nil
}
-// AddCipherForMKI adds new MKI with associated masker key and salt. Context must be created with MasterKeyIndicator option
+// AddCipherForMKI adds new MKI with associated masker key and salt.
+// Context must be created with MasterKeyIndicator option
// to enable MKI support. MKI must be unique and have the same length as the one used for creating Context.
// Operation is not thread-safe, you need to provide synchronization with decrypting packets.
func (c *Context) AddCipherForMKI(mki, masterKey, masterSalt []byte) error {
@@ -126,6 +168,7 @@ func (c *Context) AddCipherForMKI(mki, masterKey, masterSalt []byte) error {
return err
}
c.mkis[string(mki)] = cipher
+
return nil
}
@@ -141,18 +184,26 @@ func (c *Context) createCipher(mki, masterKey, masterSalt []byte, encryptSRTP, e
}
if masterKeyLen := len(masterKey); masterKeyLen != keyLen {
- return nil, fmt.Errorf("%w expected(%d) actual(%d)", errShortSrtpMasterKey, masterKey, keyLen)
+ return nil, fmt.Errorf("%w expected(%d) actual(%d)", errShortSrtpMasterKey, keyLen, masterKey)
} else if masterSaltLen := len(masterSalt); masterSaltLen != saltLen {
return nil, fmt.Errorf("%w expected(%d) actual(%d)", errShortSrtpMasterSalt, saltLen, masterSaltLen)
}
+ profileWithArgs := protectionProfileWithArgs{
+ ProtectionProfile: c.profile,
+ authTagRTPLen: c.authTagRTPLen,
+ }
+
switch c.profile {
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
- return newSrtpCipherAeadAesGcm(c.profile, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
- return newSrtpCipherAesCmHmacSha1(c.profile, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
+ return newSrtpCipherAeadAesGcm(profileWithArgs, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_80:
+ return newSrtpCipherAesCmHmacSha1(profileWithArgs, masterKey, masterSalt, mki, encryptSRTP, encryptSRTCP)
case ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
- return newSrtpCipherAesCmHmacSha1(c.profile, masterKey, masterSalt, mki, false, false)
+ return newSrtpCipherAesCmHmacSha1(profileWithArgs, masterKey, masterSalt, mki, false, false)
default:
return nil, fmt.Errorf("%w: %#v", errNoSuchSRTPProfile, c.profile)
}
@@ -168,6 +219,7 @@ func (c *Context) RemoveMKI(mki []byte) error {
return errMKIAlreadyInUse
}
delete(c.mkis, string(mki))
+
return nil
}
@@ -180,19 +232,20 @@ func (c *Context) SetSendMKI(mki []byte) error {
}
c.sendMKI = mki
c.cipher = cipher
+
return nil
}
// https://tools.ietf.org/html/rfc3550#appendix-A.1
-func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (roc uint32, diff int32, overflow bool) {
+func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (roc uint32, diff int64, overflow bool) {
seq := int32(sequenceNumber)
- localRoc := uint32(s.index >> 16)
- localSeq := int32(s.index & (seqNumMax - 1))
+ localRoc := uint32(s.index >> 16) //nolint:gosec // G115
+ localSeq := int32(s.index & (seqNumMax - 1)) //nolint:gosec // G115
guessRoc := localRoc
var difference int32
- if s.rolloverHasProcessed {
+ if s.rolloverHasProcessed { //nolint:nestif
// When localROC is equal to 0, and entering seq-localSeq > seqNumMedian
// judgment, it will cause guessRoc calculation error
if s.index > seqNumMedian {
@@ -219,16 +272,20 @@ func (s *srtpSSRCState) nextRolloverCount(sequenceNumber uint16) (roc uint32, di
}
}
- return guessRoc, difference, (guessRoc == 0 && localRoc == maxROC)
+ return guessRoc, int64(difference), (guessRoc == 0 && localRoc == maxROC)
}
-func (s *srtpSSRCState) updateRolloverCount(sequenceNumber uint16, difference int32) {
- if !s.rolloverHasProcessed {
+func (s *srtpSSRCState) updateRolloverCount(sequenceNumber uint16, difference int64, hasRemoteRoc bool,
+ remoteRoc uint32,
+) {
+ switch {
+ case hasRemoteRoc:
+ s.index = (uint64(remoteRoc) << 16) | uint64(sequenceNumber)
+ s.rolloverHasProcessed = true
+ case !s.rolloverHasProcessed:
s.index |= uint64(sequenceNumber)
s.rolloverHasProcessed = true
- return
- }
- if difference > 0 {
+ case difference > 0:
s.index += uint64(difference)
}
}
@@ -244,6 +301,7 @@ func (c *Context) getSRTPSSRCState(ssrc uint32) *srtpSSRCState {
replayDetector: c.newSRTPReplayDetector(),
}
c.srtpSSRCStates[ssrc] = s
+
return s
}
@@ -258,6 +316,7 @@ func (c *Context) getSRTCPSSRCState(ssrc uint32) *srtcpSSRCState {
replayDetector: c.newSRTCPReplayDetector(),
}
c.srtcpSSRCStates[ssrc] = s
+
return s
}
@@ -267,7 +326,8 @@ func (c *Context) ROC(ssrc uint32) (uint32, bool) {
if !ok {
return 0, false
}
- return uint32(s.index >> 16), true
+
+ return uint32(s.index >> 16), true //nolint:gosec // G115
}
// SetROC sets SRTP rollover counter value of specified SSRC.
@@ -283,6 +343,7 @@ func (c *Context) Index(ssrc uint32) (uint32, bool) {
if !ok {
return 0, false
}
+
return s.srtcpIndex, true
}
@@ -291,3 +352,49 @@ func (c *Context) SetIndex(ssrc uint32, index uint32) {
s := c.getSRTCPSSRCState(ssrc)
s.srtcpIndex = index % (maxSRTCPIndex + 1)
}
+
+//nolint:cyclop
+func (c *Context) checkRCCMode() error {
+ if c.rccMode == RCCModeNone {
+ return nil
+ }
+
+ if c.rocTransmitRate == 0 {
+ return errZeroRocTransmitRate
+ }
+
+ switch c.profile {
+ case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
+ // AEAD profiles support RCCMode3 only
+ if c.rccMode != RCCMode3 {
+ return errUnsupportedRccMode
+ }
+
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileNullHmacSha1_32:
+ if c.authTagRTPLen == nil {
+ // ROC completely replaces auth tag for _32 profiles. If you really want to use 4-byte
+ // SRTP auth tag with RCC, use SRTPAuthenticationTagLength(4) option.
+ return errTooShortSRTPAuthTag
+ }
+
+ fallthrough // Checks below are common for _32 and _80 profiles.
+
+ case ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_80,
+ ProtectionProfileNullHmacSha1_80:
+ // AES-CM and NULL profiles support RCCMode2 only
+ if c.rccMode != RCCMode2 {
+ return errUnsupportedRccMode
+ }
+ if c.authTagRTPLen != nil && *c.authTagRTPLen < 4 {
+ return errTooShortSRTPAuthTag
+ }
+
+ default:
+ return errUnsupportedRccMode
+ }
+
+ return nil
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/crypto.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/crypto.go
index 3f1913017..4c82f81b6 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/crypto.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/crypto.go
@@ -55,5 +55,6 @@ func xorBytesCTR(block cipher.Block, iv []byte, dst, src []byte) error {
}
i += n
}
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/errors.go
index c22653f0b..e46da068b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/errors.go
@@ -9,9 +9,9 @@ import (
)
var (
- // ErrFailedToVerifyAuthTag is returned when decryption fails due to invalid authentication tag
+ // ErrFailedToVerifyAuthTag is returned when decryption fails due to invalid authentication tag.
ErrFailedToVerifyAuthTag = errors.New("failed to verify auth tag")
- // ErrMKINotFound is returned when decryption fails due to unknown MKI value in packet
+ // ErrMKINotFound is returned when decryption fails due to unknown MKI value in packet.
ErrMKINotFound = errors.New("MKI not found")
errDuplicated = errors.New("duplicated packet")
@@ -31,11 +31,16 @@ var (
errMKIAlreadyInUse = errors.New("MKI already in use")
errMKIIsNotEnabled = errors.New("MKI is not enabled")
errInvalidMKILength = errors.New("invalid MKI length")
+ errTooLongSRTPAuthTag = errors.New("SRTP auth tag is too long")
+ errTooShortSRTPAuthTag = errors.New("SRTP auth tag is too short")
errStreamNotInited = errors.New("stream has not been inited, unable to close")
errStreamAlreadyClosed = errors.New("stream is already closed")
errStreamAlreadyInited = errors.New("stream is already inited")
errFailedTypeAssertion = errors.New("failed to cast child")
+
+ errZeroRocTransmitRate = errors.New("ROC transmit rate is zero")
+ errUnsupportedRccMode = errors.New("unsupported RCC mode")
)
type duplicatedError struct {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/key_derivation.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/key_derivation.go
index f192fafcc..945b569b8 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/key_derivation.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/key_derivation.go
@@ -40,6 +40,7 @@ func aesCmKeyDerivation(label byte, masterKey, masterSalt []byte, indexOverKdr i
block.Encrypt(out[n:n+nBlockSize], prfIn)
i++
}
+
return out[:outLen], nil
}
@@ -50,8 +51,12 @@ func aesCmKeyDerivation(label byte, masterKey, masterSalt []byte, indexOverKdr i
// - times the 16-bit RTP sequence number has been reset to zero after
// - passing through 65,535
// i = 2^16 * ROC + SEQ
-// IV = (salt*2 ^ 16) | (ssrc*2 ^ 64) | (i*2 ^ 16)
-func generateCounter(sequenceNumber uint16, rolloverCounter uint32, ssrc uint32, sessionSalt []byte) (counter [16]byte) {
+// IV = (salt*2 ^ 16) | (ssrc*2 ^ 64) | (i*2 ^ 16).
+func generateCounter(
+ sequenceNumber uint16,
+ rolloverCounter uint32,
+ ssrc uint32, sessionSalt []byte,
+) (counter [16]byte) {
copy(counter[:], sessionSalt)
counter[4] ^= byte(ssrc >> 24)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/keying.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/keying.go
index 617f4d71c..c9dc183c2 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/keying.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/keying.go
@@ -5,7 +5,7 @@ package srtp
const labelExtractorDtlsSrtp = "EXTRACTOR-dtls_srtp"
-// KeyingMaterialExporter allows package SRTP to extract keying material
+// KeyingMaterialExporter allows package SRTP to extract keying material.
type KeyingMaterialExporter interface {
ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error)
}
@@ -46,6 +46,7 @@ func (c *Config) ExtractSessionKeysFromDTLS(exporter KeyingMaterialExporter, isC
c.Keys.LocalMasterSalt = clientWriteKey[keyLen:]
c.Keys.RemoteMasterKey = serverWriteKey[0:keyLen]
c.Keys.RemoteMasterSalt = serverWriteKey[keyLen:]
+
return nil
}
@@ -53,5 +54,6 @@ func (c *Config) ExtractSessionKeysFromDTLS(exporter KeyingMaterialExporter, isC
c.Keys.LocalMasterSalt = serverWriteKey[keyLen:]
c.Keys.RemoteMasterKey = clientWriteKey[0:keyLen]
c.Keys.RemoteMasterSalt = clientWriteKey[keyLen:]
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/option.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/option.go
index dac0bcf1d..e9c6f8744 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/option.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/option.go
@@ -16,6 +16,7 @@ func SRTPReplayProtection(windowSize uint) ContextOption { // nolint:revive
c.newSRTPReplayDetector = func() replaydetector.ReplayDetector {
return replaydetector.New(windowSize, maxROC<<16|maxSequenceNumber)
}
+
return nil
}
}
@@ -26,6 +27,7 @@ func SRTCPReplayProtection(windowSize uint) ContextOption {
c.newSRTCPReplayDetector = func() replaydetector.ReplayDetector {
return replaydetector.New(windowSize, maxSRTCPIndex)
}
+
return nil
}
}
@@ -36,6 +38,7 @@ func SRTPNoReplayProtection() ContextOption { // nolint:revive
c.newSRTPReplayDetector = func() replaydetector.ReplayDetector {
return &nopReplayDetector{}
}
+
return nil
}
}
@@ -46,6 +49,7 @@ func SRTCPNoReplayProtection() ContextOption {
c.newSRTCPReplayDetector = func() replaydetector.ReplayDetector {
return &nopReplayDetector{}
}
+
return nil
}
}
@@ -54,6 +58,7 @@ func SRTCPNoReplayProtection() ContextOption {
func SRTPReplayDetectorFactory(fn func() replaydetector.ReplayDetector) ContextOption { // nolint:revive
return func(c *Context) error {
c.newSRTPReplayDetector = fn
+
return nil
}
}
@@ -62,6 +67,7 @@ func SRTPReplayDetectorFactory(fn func() replaydetector.ReplayDetector) ContextO
func SRTCPReplayDetectorFactory(fn func() replaydetector.ReplayDetector) ContextOption {
return func(c *Context) error {
c.newSRTCPReplayDetector = fn
+
return nil
}
}
@@ -81,6 +87,7 @@ func MasterKeyIndicator(mki []byte) ContextOption {
c.sendMKI = make([]byte, len(mki))
copy(c.sendMKI, mki)
}
+
return nil
}
}
@@ -89,15 +96,20 @@ func MasterKeyIndicator(mki []byte) ContextOption {
func SRTPEncryption() ContextOption { // nolint:revive
return func(c *Context) error {
c.encryptSRTP = true
+
return nil
}
}
-// SRTPNoEncryption disables SRTP encryption. This option is useful when you want to use NullCipher for SRTP and keep authentication only.
+// SRTPNoEncryption disables SRTP encryption.
+// This option is useful when you want to use NullCipher for SRTP and keep authentication only.
// It simplifies debugging and testing, but it is not recommended for production use.
+//
+// Note: you can also use SRTPAuthenticationTagLength(0) to disable authentication tag too.
func SRTPNoEncryption() ContextOption { // nolint:revive
return func(c *Context) error {
c.encryptSRTP = false
+
return nil
}
}
@@ -106,15 +118,58 @@ func SRTPNoEncryption() ContextOption { // nolint:revive
func SRTCPEncryption() ContextOption {
return func(c *Context) error {
c.encryptSRTCP = true
+
return nil
}
}
-// SRTCPNoEncryption disables SRTCP encryption. This option is useful when you want to use NullCipher for SRTCP and keep authentication only.
+// SRTCPNoEncryption disables SRTCP encryption.
+// This option is useful when you want to use NullCipher for SRTCP and keep authentication only.
// It simplifies debugging and testing, but it is not recommended for production use.
func SRTCPNoEncryption() ContextOption {
return func(c *Context) error {
c.encryptSRTCP = false
+
+ return nil
+ }
+}
+
+// RolloverCounterCarryingTransform enables Rollover Counter Carrying Transform from RFC 4771.
+// ROC value is sent in Authentication Tag of SRTP packets every rocTransmitRate packets.
+//
+// RFC 4771 defines 3 RCC modes. pion/srtp supports mode RCCm2 for AES-CM and NULL profiles,
+// and mode RCCm3 for AES-GCM (AEAD) profiles.
+//
+// From RFC 4771: "[For modes RCCm1 and and RCCm3] the length of the MAC is shorter than the length
+// of the authentication tag. To achieve the same (or less) MAC forgery success probability on all
+// packets when using RCCm1 or RCCm2, as with the default integrity transform in RFC 3711,
+// the tag-length must be set to 14 octets, which means that the length of MAC_tr is 10 octets."
+//
+// Protection profiles ProtectionProfile*CmHmacSha1_32 uses 4-byte SRTP auth tag, so in RCCm2 mode
+// SRTP packets with ROC will not be integrity protected.
+//
+// You can increase the length of the authentication tag using SRTPAuthenticationTagLength option
+// to mitigate this issue.
+func RolloverCounterCarryingTransform(mode RCCMode, rocTransmitRate uint16) ContextOption {
+ return func(c *Context) error {
+ c.rccMode = mode
+ c.rocTransmitRate = rocTransmitRate
+
+ return nil
+ }
+}
+
+// SRTPAuthenticationTagLength sets length of SRTP authentication tag in bytes for AES-CM protection
+// profiles. Decreasing the length of the authentication tag is not recommended for production use,
+// as it decreases integrity protection.
+//
+// Zero value means that there is no authentication tag, what may be useful for debugging and testing.
+//
+// This option is ignored for AEAD profiles.
+func SRTPAuthenticationTagLength(authTagRTPLen int) ContextOption { // nolint:revive
+ return func(c *Context) error {
+ c.authTagRTPLen = &authTagRTPLen
+
return nil
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile.go
index 9384bf8f9..181da221b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile.go
@@ -5,19 +5,25 @@ package srtp
import "fmt"
-// ProtectionProfile specifies Cipher and AuthTag details, similar to TLS cipher suite
+// ProtectionProfile specifies Cipher and AuthTag details, similar to TLS cipher suite.
type ProtectionProfile uint16
// Supported protection profiles
// See https://www.iana.org/assignments/srtp-protection/srtp-protection.xhtml
//
-// AES128_CM_HMAC_SHA1_80 and AES128_CM_HMAC_SHA1_32 are valid SRTP profiles, but they do not have an DTLS-SRTP Protection Profiles ID assigned
-// in RFC 5764. They were in earlier draft of this RFC: https://datatracker.ietf.org/doc/html/draft-ietf-avt-dtls-srtp-03#section-4.1.2
+// AES128_CM_HMAC_SHA1_80 and AES128_CM_HMAC_SHA1_32 are valid SRTP profiles,
+// but they do not have an DTLS-SRTP Protection Profiles ID assigned
+// in RFC 5764. They were in earlier draft of this RFC:
+// https://datatracker.ietf.org/doc/html/draft-ietf-avt-dtls-srtp-03#section-4.1.2
// Their IDs are now marked as reserved in the IANA registry. Despite this Chrome supports them:
// https://chromium.googlesource.com/chromium/deps/libsrtp/+/84122798bb16927b1e676bd4f938a6e48e5bf2fe/srtp/include/srtp.h#694
//
-// Null profiles disable encryption, they are used for debugging and testing. They are not recommended for production use.
-// Use of them is equivalent to using ProtectionProfileAes128CmHmacSha1_NN profile with SRTPNoEncryption and SRTCPNoEncryption options.
+// Null profiles disable encryption, they are used for debugging and testing.
+// They are not recommended for production use.
+// Use of them is equivalent to using ProtectionProfileAes128CmHmacSha1_NN
+// profile with SRTPNoEncryption and SRTCPNoEncryption options.
+//
+//nolint:lll
const (
ProtectionProfileAes128CmHmacSha1_80 ProtectionProfile = 0x0001
ProtectionProfileAes128CmHmacSha1_32 ProtectionProfile = 0x0002
@@ -29,10 +35,16 @@ const (
ProtectionProfileAeadAes256Gcm ProtectionProfile = 0x0008
)
-// KeyLen returns length of encryption key in bytes. For all profiles except NullHmacSha1_32 and NullHmacSha1_80 is is also the length of the session key.
+// KeyLen returns length of encryption key in bytes.
+// For all profiles except NullHmacSha1_32 and NullHmacSha1_80 is
+// also the length of the session key.
func (p ProtectionProfile) KeyLen() (int, error) {
switch p {
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAeadAes128Gcm, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAeadAes128Gcm,
+ ProtectionProfileNullHmacSha1_32,
+ ProtectionProfileNullHmacSha1_80:
return 16, nil
case ProtectionProfileAeadAes256Gcm, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80:
return 32, nil
@@ -41,10 +53,17 @@ func (p ProtectionProfile) KeyLen() (int, error) {
}
}
-// SaltLen returns length of salt key in bytes. For all profiles except NullHmacSha1_32 and NullHmacSha1_80 is is also the length of the session salt.
+// SaltLen returns length of salt key in bytes.
+// For all profiles except NullHmacSha1_32 and NullHmacSha1_80
+// is also the length of the session salt.
func (p ProtectionProfile) SaltLen() (int, error) {
switch p {
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_80,
+ ProtectionProfileNullHmacSha1_32,
+ ProtectionProfileNullHmacSha1_80:
return 14, nil
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
return 12, nil
@@ -53,7 +72,8 @@ func (p ProtectionProfile) SaltLen() (int, error) {
}
}
-// AuthTagRTPLen returns length of RTP authentication tag in bytes for AES protection profiles. For AEAD ones it returns zero.
+// AuthTagRTPLen returns length of RTP authentication tag in bytes for AES protection profiles.
+// For AEAD ones it returns zero.
func (p ProtectionProfile) AuthTagRTPLen() (int, error) {
switch p {
case ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_80:
@@ -67,10 +87,17 @@ func (p ProtectionProfile) AuthTagRTPLen() (int, error) {
}
}
-// AuthTagRTCPLen returns length of RTCP authentication tag in bytes for AES protection profiles. For AEAD ones it returns zero.
+// AuthTagRTCPLen returns length of RTCP authentication tag in bytes for AES protection profiles.
+//
+// For AEAD ones it returns zero.
func (p ProtectionProfile) AuthTagRTCPLen() (int, error) {
switch p {
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_80,
+ ProtectionProfileNullHmacSha1_32,
+ ProtectionProfileNullHmacSha1_80:
return 10, nil
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
return 0, nil
@@ -79,10 +106,16 @@ func (p ProtectionProfile) AuthTagRTCPLen() (int, error) {
}
}
-// AEADAuthTagLen returns length of authentication tag in bytes for AEAD protection profiles. For AES ones it returns zero.
+// AEADAuthTagLen returns length of authentication tag in bytes for AEAD protection profiles.
+// For AES ones it returns zero.
func (p ProtectionProfile) AEADAuthTagLen() (int, error) {
switch p {
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_80,
+ ProtectionProfileNullHmacSha1_32,
+ ProtectionProfileNullHmacSha1_80:
return 0, nil
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
return 16, nil
@@ -91,10 +124,16 @@ func (p ProtectionProfile) AEADAuthTagLen() (int, error) {
}
}
-// AuthKeyLen returns length of authentication key in bytes for AES protection profiles. For AEAD ones it returns zero.
+// AuthKeyLen returns length of authentication key in bytes for AES protection profiles.
+// For AEAD ones it returns zero.
func (p ProtectionProfile) AuthKeyLen() (int, error) {
switch p {
- case ProtectionProfileAes128CmHmacSha1_32, ProtectionProfileAes128CmHmacSha1_80, ProtectionProfileAes256CmHmacSha1_32, ProtectionProfileAes256CmHmacSha1_80, ProtectionProfileNullHmacSha1_32, ProtectionProfileNullHmacSha1_80:
+ case ProtectionProfileAes128CmHmacSha1_32,
+ ProtectionProfileAes128CmHmacSha1_80,
+ ProtectionProfileAes256CmHmacSha1_32,
+ ProtectionProfileAes256CmHmacSha1_80,
+ ProtectionProfileNullHmacSha1_32,
+ ProtectionProfileNullHmacSha1_80:
return 20, nil
case ProtectionProfileAeadAes128Gcm, ProtectionProfileAeadAes256Gcm:
return 0, nil
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile_with_args.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile_with_args.go
new file mode 100644
index 000000000..a0e08be4e
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/protection_profile_with_args.go
@@ -0,0 +1,21 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package srtp
+
+// protectionProfileWithArgs is a wrapper around ProtectionProfile that allows to
+// specify additional arguments for the profile.
+type protectionProfileWithArgs struct {
+ ProtectionProfile
+ authTagRTPLen *int
+}
+
+// AuthTagRTPLen returns length of RTP authentication tag in bytes for AES protection profiles.
+// For AEAD ones it returns zero.
+func (p protectionProfileWithArgs) AuthTagRTPLen() (int, error) {
+ if p.authTagRTPLen != nil {
+ return *p.authTagRTPLen, nil
+ }
+
+ return p.ProtectionProfile.AuthTagRTPLen()
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session.go
index cc4f60095..ea4e59894 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session.go
@@ -58,7 +58,7 @@ type Config struct {
LocalOptions, RemoteOptions []ContextOption
}
-// SessionKeys bundles the keys required to setup an SRTP session
+// SessionKeys bundles the keys required to setup an SRTP session.
type SessionKeys struct {
LocalMasterKey []byte
LocalMasterSalt []byte
@@ -74,20 +74,21 @@ func (s *session) getOrCreateReadStream(ssrc uint32, child streamSession, proto
return nil, false
}
- r, ok := s.readStreams[ssrc]
+ rStream, ok := s.readStreams[ssrc]
if ok {
- return r, false
+ return rStream, false
}
// Create the readStream.
- r = proto()
+ rStream = proto()
- if err := r.init(child, ssrc); err != nil {
+ if err := rStream.init(child, ssrc); err != nil {
return nil, false
}
- s.readStreams[ssrc] = r
- return r, true
+ s.readStreams[ssrc] = rStream
+
+ return rStream, true
}
func (s *session) removeReadStream(ssrc uint32) {
@@ -109,10 +110,15 @@ func (s *session) close() error {
}
<-s.closed
+
return nil
}
-func (s *session) start(localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt []byte, profile ProtectionProfile, child streamSession) error {
+func (s *session) start(
+ localMasterKey, localMasterSalt, remoteMasterKey, remoteMasterSalt []byte,
+ profile ProtectionProfile,
+ child streamSession,
+) error {
var err error
s.localContext, err = CreateContext(localMasterKey, localMasterSalt, profile, s.localOptions...)
if err != nil {
@@ -146,6 +152,7 @@ func (s *session) start(localMasterKey, localMasterSalt, remoteMasterKey, remote
if !errors.Is(err, io.EOF) {
s.log.Error(err.Error())
}
+
return
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtcp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtcp.go
index 13f1a9589..8d6f30669 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtcp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtcp.go
@@ -16,7 +16,7 @@ const defaultSessionSRTCPReplayProtectionWindow = 64
// SessionSRTCP implements io.ReadWriteCloser and provides a bi-directional SRTCP session
// SRTCP itself does not have a design like this, but it is common in most applications
// for local/remote to each have their own keying material. This provides those patterns
-// instead of making everyone re-implement
+// instead of making everyone re-implement.
type SessionSRTCP struct {
session
writeStream *WriteStreamSRTCP
@@ -47,7 +47,7 @@ func NewSessionSRTCP(conn net.Conn, config *Config) (*SessionSRTCP, error) { //n
config.RemoteOptions...,
)
- s := &SessionSRTCP{
+ srtcpSession := &SessionSRTCP{
session: session{
nextConn: conn,
localOptions: localOpts,
@@ -61,37 +61,39 @@ func NewSessionSRTCP(conn net.Conn, config *Config) (*SessionSRTCP, error) { //n
log: loggerFactory.NewLogger("srtp"),
},
}
- s.writeStream = &WriteStreamSRTCP{s}
+ srtcpSession.writeStream = &WriteStreamSRTCP{srtcpSession}
- err := s.session.start(
+ err := srtcpSession.session.start(
config.Keys.LocalMasterKey, config.Keys.LocalMasterSalt,
config.Keys.RemoteMasterKey, config.Keys.RemoteMasterSalt,
config.Profile,
- s,
+ srtcpSession,
)
if err != nil {
return nil, err
}
- return s, nil
+
+ return srtcpSession, nil
}
-// OpenWriteStream returns the global write stream for the Session
+// OpenWriteStream returns the global write stream for the Session.
func (s *SessionSRTCP) OpenWriteStream() (*WriteStreamSRTCP, error) {
return s.writeStream, nil
}
// OpenReadStream opens a read stream for the given SSRC, it can be used
-// if you want a certain SSRC, but don't want to wait for AcceptStream
+// if you want a certain SSRC, but don't want to wait for AcceptStream.
func (s *SessionSRTCP) OpenReadStream(ssrc uint32) (*ReadStreamSRTCP, error) {
r, _ := s.session.getOrCreateReadStream(ssrc, s, newReadStreamSRTCP)
if readStream, ok := r.(*ReadStreamSRTCP); ok {
return readStream, nil
}
+
return nil, errFailedTypeAssertion
}
-// AcceptStream returns a stream to handle RTCP for a single SSRC
+// AcceptStream returns a stream to handle RTCP for a single SSRC.
func (s *SessionSRTCP) AcceptStream() (*ReadStreamSRTCP, uint32, error) {
stream, ok := <-s.newStream
if !ok {
@@ -106,7 +108,7 @@ func (s *SessionSRTCP) AcceptStream() (*ReadStreamSRTCP, uint32, error) {
return readStream, stream.GetSSRC(), nil
}
-// Close ends the session
+// Close ends the session.
func (s *SessionSRTCP) Close() error {
return s.session.close()
}
@@ -122,12 +124,13 @@ func (s *SessionSRTCP) write(buf []byte) (int, error) {
defer bufferpool.Put(ibuf)
s.session.localContextMutex.Lock()
- encrypted, err := s.localContext.EncryptRTCP(ibuf.([]byte), buf, nil)
+ encrypted, err := s.localContext.EncryptRTCP(ibuf.([]byte), buf, nil) //nolint:forcetypeassert
s.session.localContextMutex.Unlock()
if err != nil {
return 0, err
}
+
return s.session.nextConn.Write(encrypted)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtp.go
index e07cbe216..5512255f1 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/session_srtp.go
@@ -17,7 +17,7 @@ const defaultSessionSRTPReplayProtectionWindow = 64
// SessionSRTP implements io.ReadWriteCloser and provides a bi-directional SRTP session
// SRTP itself does not have a design like this, but it is common in most applications
// for local/remote to each have their own keying material. This provides those patterns
-// instead of making everyone re-implement
+// instead of making everyone re-implement.
type SessionSRTP struct {
session
writeStream *WriteStreamSRTP
@@ -48,7 +48,7 @@ func NewSessionSRTP(conn net.Conn, config *Config) (*SessionSRTP, error) { //nol
config.RemoteOptions...,
)
- s := &SessionSRTP{
+ srtpSession := &SessionSRTP{
session: session{
nextConn: conn,
localOptions: localOpts,
@@ -62,27 +62,28 @@ func NewSessionSRTP(conn net.Conn, config *Config) (*SessionSRTP, error) { //nol
log: loggerFactory.NewLogger("srtp"),
},
}
- s.writeStream = &WriteStreamSRTP{s}
+ srtpSession.writeStream = &WriteStreamSRTP{srtpSession}
- err := s.session.start(
+ err := srtpSession.session.start(
config.Keys.LocalMasterKey, config.Keys.LocalMasterSalt,
config.Keys.RemoteMasterKey, config.Keys.RemoteMasterSalt,
config.Profile,
- s,
+ srtpSession,
)
if err != nil {
return nil, err
}
- return s, nil
+
+ return srtpSession, nil
}
-// OpenWriteStream returns the global write stream for the Session
+// OpenWriteStream returns the global write stream for the Session.
func (s *SessionSRTP) OpenWriteStream() (*WriteStreamSRTP, error) {
return s.writeStream, nil
}
// OpenReadStream opens a read stream for the given SSRC, it can be used
-// if you want a certain SSRC, but don't want to wait for AcceptStream
+// if you want a certain SSRC, but don't want to wait for AcceptStream.
func (s *SessionSRTP) OpenReadStream(ssrc uint32) (*ReadStreamSRTP, error) {
r, _ := s.session.getOrCreateReadStream(ssrc, s, newReadStreamSRTP)
@@ -93,7 +94,7 @@ func (s *SessionSRTP) OpenReadStream(ssrc uint32) (*ReadStreamSRTP, error) {
return nil, errFailedTypeAssertion
}
-// AcceptStream returns a stream to handle RTCP for a single SSRC
+// AcceptStream returns a stream to handle RTCP for a single SSRC.
func (s *SessionSRTP) AcceptStream() (*ReadStreamSRTP, uint32, error) {
stream, ok := <-s.newStream
if !ok {
@@ -108,7 +109,7 @@ func (s *SessionSRTP) AcceptStream() (*ReadStreamSRTP, uint32, error) {
return readStream, stream.GetSSRC(), nil
}
-// Close ends the session
+// Close ends the session.
func (s *SessionSRTP) Close() error {
return s.session.close()
}
@@ -149,8 +150,20 @@ func (s *SessionSRTP) writeRTP(header *rtp.Header, payload []byte) (int, error)
ibuf := bufferpool.Get()
defer bufferpool.Put(ibuf)
+ buf := ibuf.([]byte) // nolint:forcetypeassert
+ headerLen, marshalSize := rtp.HeaderAndPacketMarshalSize(header, payload) // nolint:staticcheck
+ if len(buf) < marshalSize+20 {
+ // The buffer is too small, so we need to allocate a new one. Add 20 bytes for auth tag like
+ // for bufferpool above.
+ buf = make([]byte, marshalSize+20)
+ }
+ _, err := rtp.MarshalPacketTo(buf, header, payload) // nolint:staticcheck
+ if err != nil {
+ return 0, err
+ }
+
s.session.localContextMutex.Lock()
- encrypted, err := s.localContext.encryptRTP(ibuf.([]byte), header, payload)
+ encrypted, err := s.localContext.encryptRTP(buf, header, headerLen, buf[:marshalSize])
s.session.localContextMutex.Unlock()
if err != nil {
@@ -165,13 +178,13 @@ func (s *SessionSRTP) setWriteDeadline(t time.Time) error {
}
func (s *SessionSRTP) decrypt(buf []byte) error {
- h := &rtp.Header{}
- headerLen, err := h.Unmarshal(buf)
+ header := &rtp.Header{}
+ headerLen, err := header.Unmarshal(buf)
if err != nil {
return err
}
- r, isNew := s.session.getOrCreateReadStream(h.SSRC, s, newReadStreamSRTP)
+ r, isNew := s.session.getOrCreateReadStream(header.SSRC, s, newReadStreamSRTP)
if r == nil {
return nil // Session has been closed
} else if isNew {
@@ -186,7 +199,7 @@ func (s *SessionSRTP) decrypt(buf []byte) error {
return errFailedTypeAssertion
}
- decrypted, err := s.remoteContext.decryptRTP(buf, buf, h, headerLen)
+ decrypted, err := s.remoteContext.decryptRTP(buf, buf, header, headerLen)
if err != nil {
return err
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtcp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtcp.go
index 6d1a1c1d9..6f7050806 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtcp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtcp.go
@@ -10,9 +10,23 @@ import (
"github.com/pion/rtcp"
)
-const maxSRTCPIndex = 0x7FFFFFFF
+/*
+Simplified structure of SRTCP Packets:
+- RTCP Header
+- Payload
+- AEAD Auth Tag - used by AEAD profiles only
+- E flag and SRTCP Index
+- MKI (optional)
+- Auth Tag - used by non-AEAD profiles only
+*/
-const srtcpHeaderSize = 8
+const (
+ maxSRTCPIndex = 0x7FFFFFFF
+
+ srtcpHeaderSize = 8
+ srtcpIndexSize = 4
+ srtcpEncryptionFlag = 0x80
+)
func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
authTagLen, err := c.cipher.AuthTagRTCPLen()
@@ -42,25 +56,24 @@ func (c *Context) decryptRTCP(dst, encrypted []byte) ([]byte, error) {
cipher := c.cipher
if len(c.mkis) > 0 {
// Find cipher for MKI
- actualMKI := c.cipher.getMKI(encrypted, false)
+ actualMKI := encrypted[len(encrypted)-mkiLen-authTagLen : len(encrypted)-authTagLen]
cipher, ok = c.mkis[string(actualMKI)]
if !ok {
return nil, ErrMKINotFound
}
}
- out := allocateIfMismatch(dst, encrypted)
-
- out, err = cipher.decryptRTCP(out, encrypted, index, ssrc)
+ out, err := cipher.decryptRTCP(dst, encrypted, index, ssrc)
if err != nil {
return nil, err
}
markAsValid()
+
return out, nil
}
-// DecryptRTCP decrypts a buffer that contains a RTCP packet
+// DecryptRTCP decrypts a buffer that contains a RTCP packet.
func (c *Context) DecryptRTCP(dst, encrypted []byte, header *rtcp.Header) ([]byte, error) {
if header == nil {
header = &rtcp.Header{}
@@ -79,9 +92,9 @@ func (c *Context) encryptRTCP(dst, decrypted []byte) ([]byte, error) {
}
ssrc := binary.BigEndian.Uint32(decrypted[4:])
- s := c.getSRTCPSSRCState(ssrc)
+ ssrcState := c.getSRTCPSSRCState(ssrc)
- if s.srtcpIndex >= maxSRTCPIndex {
+ if ssrcState.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.
@@ -90,12 +103,12 @@ func (c *Context) encryptRTCP(dst, decrypted []byte) ([]byte, error) {
}
// We roll over early because MSB is used for marking as encrypted
- s.srtcpIndex++
+ ssrcState.srtcpIndex++
- return c.cipher.encryptRTCP(dst, decrypted, s.srtcpIndex, ssrc)
+ return c.cipher.encryptRTCP(dst, decrypted, ssrcState.srtcpIndex, ssrc)
}
-// EncryptRTCP Encrypts a RTCP packet
+// EncryptRTCP Encrypts a RTCP packet.
func (c *Context) EncryptRTCP(dst, decrypted []byte, header *rtcp.Header) ([]byte, error) {
if header == nil {
header = &rtcp.Header{}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp.go
index 56828bcf4..89e427f13 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp.go
@@ -5,11 +5,21 @@
package srtp
import (
+ "encoding/binary"
"fmt"
"github.com/pion/rtp"
)
+/*
+Simplified structure of SRTP Packets:
+- RTP Header (with optional RTP Header Extension)
+- Payload (with optional padding)
+- AEAD Auth Tag - used by AEAD profiles only
+- MKI (optional)
+- Auth Tag - used by non-AEAD profiles only. When RCC is used with AEAD profiles, the ROC is sent here.
+*/
+
func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerLen int) ([]byte, error) {
authTagLen, err := c.cipher.AuthTagRTPLen()
if err != nil {
@@ -21,17 +31,31 @@ func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerL
}
mkiLen := len(c.sendMKI)
+ var hasRocInPacket bool
+ hasRocInPacket, authTagLen = c.hasROCInPacket(header, authTagLen)
+
// Verify that encrypted packet is long enough
if len(ciphertext) < (headerLen + aeadAuthTagLen + mkiLen + authTagLen) {
return nil, fmt.Errorf("%w: %d", errTooShortRTP, len(ciphertext))
}
- s := c.getSRTPSSRCState(header.SSRC)
+ ssrcState := c.getSRTPSSRCState(header.SSRC)
- roc, diff, _ := s.nextRolloverCount(header.SequenceNumber)
- markAsValid, ok := s.replayDetector.Check(
- (uint64(roc) << 16) | uint64(header.SequenceNumber),
- )
+ var roc uint32
+ var diff int64
+ var index uint64
+ if !hasRocInPacket {
+ // The ROC is not sent in the packet. We need to guess it.
+ roc, diff, _ = ssrcState.nextRolloverCount(header.SequenceNumber)
+ index = (uint64(roc) << 16) | uint64(header.SequenceNumber)
+ } else {
+ // Extract ROC from the packet. The ROC is sent in the first 4 bytes of the auth tag.
+ roc = binary.BigEndian.Uint32(ciphertext[len(ciphertext)-authTagLen:])
+ index = (uint64(roc) << 16) | uint64(header.SequenceNumber)
+ diff = int64(ssrcState.index) - int64(index) //nolint:gosec
+ }
+
+ markAsValid, ok := ssrcState.replayDetector.Check(index)
if !ok {
return nil, &duplicatedError{
Proto: "srtp", SSRC: header.SSRC, Index: uint32(header.SequenceNumber),
@@ -41,7 +65,7 @@ func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerL
cipher := c.cipher
if len(c.mkis) > 0 {
// Find cipher for MKI
- actualMKI := c.cipher.getMKI(ciphertext, true)
+ actualMKI := ciphertext[len(ciphertext)-mkiLen-authTagLen : len(ciphertext)-authTagLen]
cipher, ok = c.mkis[string(actualMKI)]
if !ok {
return nil, ErrMKINotFound
@@ -50,17 +74,18 @@ func (c *Context) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerL
dst = growBufferSize(dst, len(ciphertext)-authTagLen-len(c.sendMKI))
- dst, err = cipher.decryptRTP(dst, ciphertext, header, headerLen, roc)
+ dst, err = cipher.decryptRTP(dst, ciphertext, header, headerLen, roc, hasRocInPacket)
if err != nil {
return nil, err
}
markAsValid()
- s.updateRolloverCount(header.SequenceNumber, diff)
+ ssrcState.updateRolloverCount(header.SequenceNumber, diff, hasRocInPacket, roc)
+
return dst, nil
}
-// DecryptRTP decrypts a RTP packet with an encrypted payload
+// DecryptRTP decrypts a RTP packet with an encrypted payload.
func (c *Context) DecryptRTP(dst, encrypted []byte, header *rtp.Header) ([]byte, error) {
if header == nil {
header = &rtp.Header{}
@@ -75,7 +100,8 @@ func (c *Context) DecryptRTP(dst, encrypted []byte, header *rtp.Header) ([]byte,
}
// EncryptRTP marshals and encrypts an RTP packet, writing to the dst buffer provided.
-// If the dst buffer does not have the capacity to hold `len(plaintext) + 10` bytes, a new one will be allocated and returned.
+// If the dst buffer does not have the capacity to hold `len(plaintext) + 10` bytes,
+// a new one will be allocated and returned.
// If a rtp.Header is provided, it will be Unmarshaled using the plaintext.
func (c *Context) EncryptRTP(dst []byte, plaintext []byte, header *rtp.Header) ([]byte, error) {
if header == nil {
@@ -87,13 +113,14 @@ func (c *Context) EncryptRTP(dst []byte, plaintext []byte, header *rtp.Header) (
return nil, err
}
- return c.encryptRTP(dst, header, plaintext[headerLen:])
+ return c.encryptRTP(dst, header, headerLen, plaintext)
}
// encryptRTP marshals and encrypts an RTP packet, writing to the dst buffer provided.
// If the dst buffer does not have the capacity, a new one will be allocated and returned.
// 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) {
+func (c *Context) encryptRTP(dst []byte, header *rtp.Header, headerLen int, plaintext []byte,
+) (ciphertext []byte, err error) {
s := c.getSRTPSSRCState(header.SSRC)
roc, diff, ovf := s.nextRolloverCount(header.SequenceNumber)
if ovf {
@@ -103,7 +130,30 @@ func (c *Context) encryptRTP(dst []byte, header *rtp.Header, payload []byte) (ci
// https://www.rfc-editor.org/rfc/rfc3711#section-9.2
return nil, errExceededMaxPackets
}
- s.updateRolloverCount(header.SequenceNumber, diff)
+ s.updateRolloverCount(header.SequenceNumber, diff, false, 0)
- return c.cipher.encryptRTP(dst, header, payload, roc)
+ rocInPacket := false
+ if c.rccMode != RCCModeNone && header.SequenceNumber%c.rocTransmitRate == 0 {
+ rocInPacket = true
+ }
+
+ return c.cipher.encryptRTP(dst, header, headerLen, plaintext, roc, rocInPacket)
+}
+
+func (c *Context) hasROCInPacket(header *rtp.Header, authTagLen int) (bool, int) {
+ hasRocInPacket := false
+ switch c.rccMode {
+ case RCCMode2:
+ // This mode is supported for AES-CM and NULL profiles only. The ROC is sent in the first 4 bytes of the auth tag.
+ hasRocInPacket = header.SequenceNumber%c.rocTransmitRate == 0
+ case RCCMode3:
+ // This mode is supported for AES-GCM only. The ROC is sent as 4-byte auth tag.
+ hasRocInPacket = header.SequenceNumber%c.rocTransmitRate == 0
+ if hasRocInPacket {
+ authTagLen = 4
+ }
+ default:
+ }
+
+ return hasRocInPacket, authTagLen
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher.go
index da745e7cd..3464e3e62 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher.go
@@ -6,7 +6,7 @@ package srtp
import "github.com/pion/rtp"
// cipher represents a implementation of one
-// of the SRTP Specific ciphers
+// of the SRTP Specific ciphers.
type srtpCipher interface {
// AuthTagRTPLen/AuthTagRTCPLen return auth key length of the cipher.
// See the note below.
@@ -16,12 +16,11 @@ type srtpCipher interface {
// See the note below.
AEADAuthTagLen() (int, error)
getRTCPIndex([]byte) uint32
- getMKI([]byte, bool) []byte
- encryptRTP([]byte, *rtp.Header, []byte, uint32) ([]byte, error)
+ encryptRTP([]byte, *rtp.Header, int, []byte, uint32, bool) ([]byte, error)
encryptRTCP([]byte, []byte, uint32, uint32) ([]byte, error)
- decryptRTP([]byte, []byte, *rtp.Header, int, uint32) ([]byte, error)
+ decryptRTP([]byte, []byte, *rtp.Header, int, uint32, bool) ([]byte, error)
decryptRTCP([]byte, []byte, uint32, uint32) ([]byte, error)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aead_aes_gcm.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aead_aes_gcm.go
index 64f890fa9..3dbb1424c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aead_aes_gcm.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aead_aes_gcm.go
@@ -12,12 +12,8 @@ import (
"github.com/pion/rtp"
)
-const (
- rtcpEncryptionFlag = 0x80
-)
-
type srtpCipherAeadAesGcm struct {
- ProtectionProfile
+ protectionProfileWithArgs
srtpCipher, srtcpCipher cipher.AEAD
@@ -28,11 +24,15 @@ type srtpCipherAeadAesGcm struct {
srtpEncrypted, srtcpEncrypted bool
}
-func newSrtpCipherAeadAesGcm(profile ProtectionProfile, masterKey, masterSalt, mki []byte, encryptSRTP, encryptSRTCP bool) (*srtpCipherAeadAesGcm, error) {
- s := &srtpCipherAeadAesGcm{
- ProtectionProfile: profile,
- srtpEncrypted: encryptSRTP,
- srtcpEncrypted: encryptSRTCP,
+func newSrtpCipherAeadAesGcm(
+ profile protectionProfileWithArgs,
+ masterKey, masterSalt, mki []byte,
+ encryptSRTP, encryptSRTCP bool,
+) (*srtpCipherAeadAesGcm, error) {
+ srtpCipher := &srtpCipherAeadAesGcm{
+ protectionProfileWithArgs: profile,
+ srtpEncrypted: encryptSRTP,
+ srtcpEncrypted: encryptSRTCP,
}
srtpSessionKey, err := aesCmKeyDerivation(labelSRTPEncryption, masterKey, masterSalt, 0, len(masterKey))
@@ -45,7 +45,7 @@ func newSrtpCipherAeadAesGcm(profile ProtectionProfile, masterKey, masterSalt, m
return nil, err
}
- s.srtpCipher, err = cipher.NewGCM(srtpBlock)
+ srtpCipher.srtpCipher, err = cipher.NewGCM(srtpBlock)
if err != nil {
return nil, err
}
@@ -60,72 +60,109 @@ func newSrtpCipherAeadAesGcm(profile ProtectionProfile, masterKey, masterSalt, m
return nil, err
}
- s.srtcpCipher, err = cipher.NewGCM(srtcpBlock)
+ srtpCipher.srtcpCipher, err = cipher.NewGCM(srtcpBlock)
if err != nil {
return nil, err
}
- if s.srtpSessionSalt, err = aesCmKeyDerivation(labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ if srtpCipher.srtpSessionSalt, err = aesCmKeyDerivation(
+ labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt),
+ ); err != nil {
return nil, err
- } else if s.srtcpSessionSalt, err = aesCmKeyDerivation(labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ } else if srtpCipher.srtcpSessionSalt, err = aesCmKeyDerivation(
+ labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt),
+ ); err != nil {
return nil, err
}
mkiLen := len(mki)
if mkiLen > 0 {
- s.mki = make([]byte, mkiLen)
- copy(s.mki, mki)
+ srtpCipher.mki = make([]byte, mkiLen)
+ copy(srtpCipher.mki, mki)
}
- return s, nil
+ return srtpCipher, nil
}
-func (s *srtpCipherAeadAesGcm) encryptRTP(dst []byte, header *rtp.Header, payload []byte, roc uint32) (ciphertext []byte, err error) {
+func (s *srtpCipherAeadAesGcm) encryptRTP(
+ dst []byte,
+ header *rtp.Header,
+ headerLen int,
+ plaintext []byte,
+ roc uint32,
+ rocInAuthTag bool,
+) (ciphertext []byte, err error) {
+ payload := plaintext[headerLen:]
+ payloadLen := len(payload)
+
// Grow the given buffer to fit the output.
authTagLen, err := s.AEADAuthTagLen()
if err != nil {
return nil, err
}
- dst = growBufferSize(dst, header.MarshalSize()+len(payload)+authTagLen+len(s.mki))
+ authPartLen := header.MarshalSize() + len(payload) + authTagLen
+ dstLen := authPartLen + len(s.mki)
+ if rocInAuthTag {
+ dstLen += 4
+ }
+ dst = growBufferSize(dst, dstLen)
+ sameBuffer := isSameBuffer(dst, plaintext)
- n, err := header.MarshalTo(dst)
- if err != nil {
- return nil, err
+ // Copy the header unencrypted.
+ if !sameBuffer {
+ copy(dst, plaintext[:headerLen])
}
iv := s.rtpInitializationVector(header, roc)
if s.srtpEncrypted {
- s.srtpCipher.Seal(dst[n:n], iv[:], payload, dst[:n])
+ s.srtpCipher.Seal(dst[headerLen:headerLen], iv[:], payload, dst[:headerLen])
} else {
- clearLen := n + len(payload)
- copy(dst[n:], payload)
+ clearLen := headerLen + payloadLen
+ if !sameBuffer {
+ copy(dst[headerLen:], payload)
+ }
s.srtpCipher.Seal(dst[clearLen:clearLen], iv[:], nil, dst[:clearLen])
}
// Add MKI after the encrypted payload
if len(s.mki) > 0 {
- copy(dst[len(dst)-len(s.mki):], s.mki)
+ copy(dst[authPartLen:], s.mki)
+ }
+
+ if rocInAuthTag {
+ binary.BigEndian.PutUint32(dst[len(dst)-4:], roc)
}
return dst, nil
}
-func (s *srtpCipherAeadAesGcm) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerLen int, roc uint32) ([]byte, error) {
+func (s *srtpCipherAeadAesGcm) decryptRTP(
+ dst, ciphertext []byte,
+ header *rtp.Header,
+ headerLen int,
+ roc uint32,
+ rocInAuthTag bool,
+) ([]byte, error) {
// Grow the given buffer to fit the output.
authTagLen, err := s.AEADAuthTagLen()
if err != nil {
return nil, err
}
- nDst := len(ciphertext) - authTagLen - len(s.mki)
+ rocLen := 0
+ if rocInAuthTag {
+ rocLen = 4
+ }
+ nDst := len(ciphertext) - authTagLen - len(s.mki) - rocLen
if nDst < headerLen {
// Size of ciphertext is shorter than AEAD auth tag len.
return nil, ErrFailedToVerifyAuthTag
}
dst = growBufferSize(dst, nDst)
+ sameBuffer := isSameBuffer(dst, ciphertext)
iv := s.rtpInitializationVector(header, roc)
- nEnd := len(ciphertext) - len(s.mki)
+ nEnd := len(ciphertext) - len(s.mki) - rocLen
if s.srtpEncrypted {
if _, err := s.srtpCipher.Open(
dst[headerLen:headerLen], iv[:], ciphertext[headerLen:nEnd], ciphertext[:headerLen],
@@ -139,10 +176,16 @@ func (s *srtpCipherAeadAesGcm) decryptRTP(dst, ciphertext []byte, header *rtp.He
); err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
}
- copy(dst[headerLen:], ciphertext[headerLen:nDataEnd])
+ if !sameBuffer {
+ copy(dst[headerLen:], ciphertext[headerLen:nDataEnd])
+ }
+ }
+
+ // Copy the header unencrypted.
+ if !sameBuffer {
+ copy(dst[:headerLen], ciphertext[:headerLen])
}
- copy(dst[:headerLen], ciphertext[:headerLen])
return dst, nil
}
@@ -154,28 +197,36 @@ func (s *srtpCipherAeadAesGcm) encryptRTCP(dst, decrypted []byte, srtcpIndex uin
aadPos := len(decrypted) + authTagLen
// Grow the given buffer to fit the output.
dst = growBufferSize(dst, aadPos+srtcpIndexSize+len(s.mki))
+ sameBuffer := isSameBuffer(dst, decrypted)
iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
if s.srtcpEncrypted {
aad := s.rtcpAdditionalAuthenticatedData(decrypted, srtcpIndex)
- copy(dst[:8], decrypted[:8])
- copy(dst[aadPos:aadPos+4], aad[8:12])
- s.srtcpCipher.Seal(dst[8:8], iv[:], decrypted[8:], aad[:])
+ if !sameBuffer {
+ // Copy the header unencrypted.
+ copy(dst[:srtcpHeaderSize], decrypted[:srtcpHeaderSize])
+ }
+ // Copy index to the proper place.
+ copy(dst[aadPos:aadPos+srtcpIndexSize], aad[8:12])
+ s.srtcpCipher.Seal(dst[srtcpHeaderSize:srtcpHeaderSize], iv[:], decrypted[srtcpHeaderSize:], aad[:])
} else {
// Copy the packet unencrypted.
- copy(dst, decrypted)
+ if !sameBuffer {
+ copy(dst, decrypted)
+ }
// Append the SRTCP index to the end of the packet - this will form the AAD.
binary.BigEndian.PutUint32(dst[len(decrypted):], srtcpIndex)
// Generate the authentication tag.
tag := make([]byte, authTagLen)
- s.srtcpCipher.Seal(tag[0:0], iv[:], nil, dst[:len(decrypted)+4])
+ s.srtcpCipher.Seal(tag[0:0], iv[:], nil, dst[:len(decrypted)+srtcpIndexSize])
// Copy index to the proper place.
- copy(dst[aadPos:], dst[len(decrypted):len(decrypted)+4])
+ copy(dst[aadPos:], dst[len(decrypted):len(decrypted)+srtcpIndexSize])
// Copy the auth tag after RTCP payload.
copy(dst[len(decrypted):], tag)
}
- copy(dst[aadPos+4:], s.mki)
+ copy(dst[aadPos+srtcpIndexSize:], s.mki)
+
return dst, nil
}
@@ -192,12 +243,14 @@ func (s *srtpCipherAeadAesGcm) decryptRTCP(dst, encrypted []byte, srtcpIndex, ss
return nil, ErrFailedToVerifyAuthTag
}
dst = growBufferSize(dst, nDst)
+ sameBuffer := isSameBuffer(dst, encrypted)
- isEncrypted := encrypted[aadPos]>>7 != 0
+ isEncrypted := encrypted[aadPos]&srtcpEncryptionFlag != 0
iv := s.rtcpInitializationVector(srtcpIndex, ssrc)
if isEncrypted {
aad := s.rtcpAdditionalAuthenticatedData(encrypted, srtcpIndex)
- if _, err := s.srtcpCipher.Open(dst[8:8], iv[:], encrypted[8:aadPos], aad[:]); err != nil {
+ if _, err := s.srtcpCipher.Open(dst[srtcpHeaderSize:srtcpHeaderSize], iv[:], encrypted[srtcpHeaderSize:aadPos],
+ aad[:]); err != nil {
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
}
} else {
@@ -211,10 +264,16 @@ func (s *srtpCipherAeadAesGcm) decryptRTCP(dst, encrypted []byte, srtcpIndex, ss
return nil, fmt.Errorf("%w: %w", ErrFailedToVerifyAuthTag, err)
}
// Copy the unencrypted payload.
- copy(dst[8:], encrypted[8:dataEnd])
+ if !sameBuffer {
+ copy(dst[srtcpHeaderSize:], encrypted[srtcpHeaderSize:dataEnd])
+ }
+ }
+
+ // Copy the header unencrypted.
+ if !sameBuffer {
+ copy(dst[:srtcpHeaderSize], encrypted[:srtcpHeaderSize])
}
- copy(dst[:8], encrypted[:8])
return dst, nil
}
@@ -233,6 +292,7 @@ func (s *srtpCipherAeadAesGcm) rtpInitializationVector(header *rtp.Header, roc u
for i := range iv {
iv[i] ^= s.srtpSessionSalt[i]
}
+
return iv
}
@@ -252,6 +312,7 @@ func (s *srtpCipherAeadAesGcm) rtcpInitializationVector(srtcpIndex uint32, ssrc
for i := range iv {
iv[i] ^= s.srtcpSessionSalt[i]
}
+
return iv
}
@@ -265,21 +326,11 @@ func (s *srtpCipherAeadAesGcm) rtcpAdditionalAuthenticatedData(rtcpPacket []byte
copy(aad[:], rtcpPacket[:8])
binary.BigEndian.PutUint32(aad[8:], srtcpIndex)
- aad[8] |= rtcpEncryptionFlag
+ aad[8] |= srtcpEncryptionFlag
return aad
}
func (s *srtpCipherAeadAesGcm) getRTCPIndex(in []byte) uint32 {
- return binary.BigEndian.Uint32(in[len(in)-len(s.mki)-4:]) &^ (rtcpEncryptionFlag << 24)
-}
-
-func (s *srtpCipherAeadAesGcm) getMKI(in []byte, _ bool) []byte {
- mkiLen := len(s.mki)
- if mkiLen == 0 {
- return nil
- }
-
- tailOffset := len(in) - mkiLen
- return in[tailOffset:]
+ return binary.BigEndian.Uint32(in[len(in)-len(s.mki)-srtcpIndexSize:]) &^ (srtcpEncryptionFlag << 24)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aes_cm_hmac_sha1.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aes_cm_hmac_sha1.go
index aa673fa94..307b6d3bb 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aes_cm_hmac_sha1.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/srtp_cipher_aes_cm_hmac_sha1.go
@@ -16,7 +16,7 @@ import ( //nolint:gci
)
type srtpCipherAesCmHmacSha1 struct {
- ProtectionProfile
+ protectionProfileWithArgs
srtpSessionSalt []byte
srtpSessionAuth hash.Hash
@@ -31,35 +31,46 @@ type srtpCipherAesCmHmacSha1 struct {
mki []byte
}
-func newSrtpCipherAesCmHmacSha1(profile ProtectionProfile, masterKey, masterSalt, mki []byte, encryptSRTP, encryptSRTCP bool) (*srtpCipherAesCmHmacSha1, error) {
- if profile == ProtectionProfileNullHmacSha1_80 || profile == ProtectionProfileNullHmacSha1_32 {
+//nolint:cyclop
+func newSrtpCipherAesCmHmacSha1(
+ profile protectionProfileWithArgs,
+ masterKey, masterSalt, mki []byte,
+ encryptSRTP, encryptSRTCP bool,
+) (*srtpCipherAesCmHmacSha1, error) {
+ switch profile.ProtectionProfile {
+ case ProtectionProfileNullHmacSha1_80, ProtectionProfileNullHmacSha1_32:
encryptSRTP = false
encryptSRTCP = false
+ default:
}
- s := &srtpCipherAesCmHmacSha1{
- ProtectionProfile: profile,
- srtpEncrypted: encryptSRTP,
- srtcpEncrypted: encryptSRTCP,
+ srtpCipher := &srtpCipherAesCmHmacSha1{
+ protectionProfileWithArgs: profile,
+ srtpEncrypted: encryptSRTP,
+ srtcpEncrypted: encryptSRTCP,
}
srtpSessionKey, err := aesCmKeyDerivation(labelSRTPEncryption, masterKey, masterSalt, 0, len(masterKey))
if err != nil {
return nil, err
- } else if s.srtpBlock, err = aes.NewCipher(srtpSessionKey); err != nil {
+ } else if srtpCipher.srtpBlock, err = aes.NewCipher(srtpSessionKey); err != nil {
return nil, err
}
srtcpSessionKey, err := aesCmKeyDerivation(labelSRTCPEncryption, masterKey, masterSalt, 0, len(masterKey))
if err != nil {
return nil, err
- } else if s.srtcpBlock, err = aes.NewCipher(srtcpSessionKey); err != nil {
+ } else if srtpCipher.srtcpBlock, err = aes.NewCipher(srtcpSessionKey); err != nil {
return nil, err
}
- if s.srtpSessionSalt, err = aesCmKeyDerivation(labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ if srtpCipher.srtpSessionSalt, err = aesCmKeyDerivation(
+ labelSRTPSalt, masterKey, masterSalt, 0, len(masterSalt),
+ ); err != nil {
return nil, err
- } else if s.srtcpSessionSalt, err = aesCmKeyDerivation(labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt)); err != nil {
+ } else if srtpCipher.srtcpSessionSalt, err = aesCmKeyDerivation(
+ labelSRTCPSalt, masterKey, masterSalt, 0, len(masterSalt),
+ ); err != nil {
return nil, err
}
@@ -78,45 +89,55 @@ func newSrtpCipherAesCmHmacSha1(profile ProtectionProfile, masterKey, masterSalt
return nil, err
}
- s.srtcpSessionAuth = hmac.New(sha1.New, srtcpSessionAuthTag)
- s.srtpSessionAuth = hmac.New(sha1.New, srtpSessionAuthTag)
+ srtpCipher.srtcpSessionAuth = hmac.New(sha1.New, srtcpSessionAuthTag)
+ srtpCipher.srtpSessionAuth = hmac.New(sha1.New, srtpSessionAuthTag)
mkiLen := len(mki)
if mkiLen > 0 {
- s.mki = make([]byte, mkiLen)
- copy(s.mki, mki)
+ srtpCipher.mki = make([]byte, mkiLen)
+ copy(srtpCipher.mki, mki)
}
- return s, nil
+ return srtpCipher, nil
}
-func (s *srtpCipherAesCmHmacSha1) encryptRTP(dst []byte, header *rtp.Header, payload []byte, roc uint32) (ciphertext []byte, err error) {
+func (s *srtpCipherAesCmHmacSha1) encryptRTP(
+ dst []byte,
+ header *rtp.Header,
+ headerLen int,
+ plaintext []byte,
+ roc uint32,
+ rocInAuthTag bool,
+) (ciphertext []byte, err error) {
+ payload := plaintext[headerLen:]
+ payloadLen := len(payload)
+
// Grow the given buffer to fit the output.
authTagLen, err := s.AuthTagRTPLen()
if err != nil {
return nil, err
}
- dst = growBufferSize(dst, header.MarshalSize()+len(payload)+len(s.mki)+authTagLen)
+ dst = growBufferSize(dst, headerLen+payloadLen+len(s.mki)+authTagLen)
+ sameBuffer := isSameBuffer(dst, plaintext)
// Copy the header unencrypted.
- n, err := header.MarshalTo(dst)
- if err != nil {
- return nil, err
+ if !sameBuffer {
+ copy(dst, plaintext[:headerLen])
}
// Encrypt the payload
if s.srtpEncrypted {
counter := generateCounter(header.SequenceNumber, roc, header.SSRC, s.srtpSessionSalt)
- if err = xorBytesCTR(s.srtpBlock, counter[:], dst[n:], payload); err != nil {
+ if err = xorBytesCTR(s.srtpBlock, counter[:], dst[headerLen:], payload); err != nil {
return nil, err
}
- } else {
- copy(dst[n:], payload)
+ } else if !sameBuffer {
+ copy(dst[headerLen:], payload)
}
- n += len(payload)
+ n := headerLen + payloadLen
// Generate the auth tag.
- authTag, err := s.generateSrtpAuthTag(dst[:n], roc)
+ authTag, err := s.generateSrtpAuthTag(dst[:n], roc, rocInAuthTag)
if err != nil {
return nil, err
}
@@ -133,7 +154,13 @@ func (s *srtpCipherAesCmHmacSha1) encryptRTP(dst []byte, header *rtp.Header, pay
return dst, nil
}
-func (s *srtpCipherAesCmHmacSha1) decryptRTP(dst, ciphertext []byte, header *rtp.Header, headerLen int, roc uint32) ([]byte, error) {
+func (s *srtpCipherAesCmHmacSha1) decryptRTP(
+ dst, ciphertext []byte,
+ header *rtp.Header,
+ headerLen int,
+ roc uint32,
+ rocInAuthTag bool,
+) ([]byte, error) {
// Split the auth tag and the cipher text into two parts.
authTagLen, err := s.AuthTagRTPLen()
if err != nil {
@@ -145,7 +172,7 @@ func (s *srtpCipherAesCmHmacSha1) decryptRTP(dst, ciphertext []byte, header *rtp
ciphertext = ciphertext[:len(ciphertext)-len(s.mki)-authTagLen]
// Generate the auth tag we expect to see from the ciphertext.
- expectedTag, err := s.generateSrtpAuthTag(ciphertext, roc)
+ expectedTag, err := s.generateSrtpAuthTag(ciphertext, roc, rocInAuthTag)
if err != nil {
return nil, err
}
@@ -156,8 +183,12 @@ func (s *srtpCipherAesCmHmacSha1) decryptRTP(dst, ciphertext []byte, header *rtp
return nil, ErrFailedToVerifyAuthTag
}
+ sameBuffer := isSameBuffer(dst, ciphertext)
+
// Write the plaintext header to the destination buffer.
- copy(dst, ciphertext[:headerLen])
+ if !sameBuffer {
+ copy(dst, ciphertext[:headerLen])
+ }
// Decrypt the ciphertext for the payload.
if s.srtpEncrypted {
@@ -168,83 +199,110 @@ func (s *srtpCipherAesCmHmacSha1) decryptRTP(dst, ciphertext []byte, header *rtp
if err != nil {
return nil, err
}
- } else {
+ } else if !sameBuffer {
copy(dst[headerLen:], ciphertext[headerLen:])
}
+
return dst, nil
}
func (s *srtpCipherAesCmHmacSha1) encryptRTCP(dst, decrypted []byte, srtcpIndex uint32, ssrc uint32) ([]byte, error) {
- dst = allocateIfMismatch(dst, decrypted)
+ authTagLen, err := s.AuthTagRTCPLen()
+ if err != nil {
+ return nil, err
+ }
+ mkiLen := len(s.mki)
+ decryptedLen := len(decrypted)
+ encryptedLen := decryptedLen + authTagLen + mkiLen + srtcpIndexSize
+
+ dst = growBufferSize(dst, encryptedLen)
+ sameBuffer := isSameBuffer(dst, decrypted)
+
+ if !sameBuffer {
+ copy(dst, decrypted[:srtcpHeaderSize]) // Copy the first 8 bytes (RTCP header)
+ }
// Encrypt everything after header
if s.srtcpEncrypted {
- counter := generateCounter(uint16(srtcpIndex&0xffff), srtcpIndex>>16, ssrc, s.srtcpSessionSalt)
- if err := xorBytesCTR(s.srtcpBlock, counter[:], dst[8:], dst[8:]); err != nil {
+ counter := generateCounter(uint16(srtcpIndex&0xffff), srtcpIndex>>16, ssrc, s.srtcpSessionSalt) //nolint:gosec // G115
+ if err = xorBytesCTR(s.srtcpBlock, counter[:], dst[srtcpHeaderSize:], decrypted[srtcpHeaderSize:]); err != nil {
return nil, err
}
// Add SRTCP Index and set Encryption bit
- dst = append(dst, make([]byte, 4)...)
- binary.BigEndian.PutUint32(dst[len(dst)-4:], srtcpIndex)
- dst[len(dst)-4] |= 0x80
+ binary.BigEndian.PutUint32(dst[decryptedLen:], srtcpIndex)
+ dst[decryptedLen] |= srtcpEncryptionFlag
} else {
// Copy the decrypted payload as is
- copy(dst[8:], decrypted[8:])
+ if !sameBuffer {
+ copy(dst[srtcpHeaderSize:], decrypted[srtcpHeaderSize:])
+ }
// Add SRTCP Index with Encryption bit cleared
- dst = append(dst, make([]byte, 4)...)
- binary.BigEndian.PutUint32(dst[len(dst)-4:], srtcpIndex)
+ binary.BigEndian.PutUint32(dst[decryptedLen:], srtcpIndex)
}
+ n := decryptedLen + srtcpIndexSize
+
// Generate the authentication tag
- authTag, err := s.generateSrtcpAuthTag(dst)
+ authTag, err := s.generateSrtcpAuthTag(dst[:n])
if err != nil {
return nil, err
}
// Include the MKI if provided
if len(s.mki) > 0 {
- dst = append(dst, s.mki...)
+ copy(dst[n:], s.mki)
+ n += mkiLen
}
// Append the auth tag at the end of the buffer
- return append(dst, authTag...), nil
+ copy(dst[n:], authTag)
+
+ return dst, nil
}
-func (s *srtpCipherAesCmHmacSha1) decryptRTCP(out, encrypted []byte, index, ssrc uint32) ([]byte, error) {
+func (s *srtpCipherAesCmHmacSha1) decryptRTCP(dst, encrypted []byte, index, ssrc uint32) ([]byte, error) {
authTagLen, err := s.AuthTagRTCPLen()
if err != nil {
return nil, err
}
- tailOffset := len(encrypted) - (authTagLen + len(s.mki) + srtcpIndexSize)
- if tailOffset < 8 {
+ mkiLen := len(s.mki)
+ encryptedLen := len(encrypted)
+ decryptedLen := encryptedLen - (authTagLen + mkiLen + srtcpIndexSize)
+ if decryptedLen < 8 {
return nil, errTooShortRTCP
}
- out = out[0:tailOffset]
- expectedTag, err := s.generateSrtcpAuthTag(encrypted[:len(encrypted)-len(s.mki)-authTagLen])
+ expectedTag, err := s.generateSrtcpAuthTag(encrypted[:encryptedLen-mkiLen-authTagLen])
if err != nil {
return nil, err
}
- actualTag := encrypted[len(encrypted)-authTagLen:]
+ actualTag := encrypted[encryptedLen-authTagLen:]
if subtle.ConstantTimeCompare(actualTag, expectedTag) != 1 {
return nil, ErrFailedToVerifyAuthTag
}
- isEncrypted := encrypted[tailOffset]>>7 != 0
- if isEncrypted {
- counter := generateCounter(uint16(index&0xffff), index>>16, ssrc, s.srtcpSessionSalt)
- err = xorBytesCTR(s.srtcpBlock, counter[:], out[8:], out[8:])
- } else {
- copy(out[8:], encrypted[8:])
+ dst = growBufferSize(dst, decryptedLen)
+ sameBuffer := isSameBuffer(dst, encrypted)
+
+ if !sameBuffer {
+ copy(dst, encrypted[:srtcpHeaderSize]) // Copy the first 8 bytes (RTCP header)
}
- return out, err
+ isEncrypted := encrypted[decryptedLen]&srtcpEncryptionFlag != 0
+ if isEncrypted {
+ counter := generateCounter(uint16(index&0xffff), index>>16, ssrc, s.srtcpSessionSalt) //nolint:gosec // G115
+ err = xorBytesCTR(s.srtcpBlock, counter[:], dst[srtcpHeaderSize:], encrypted[srtcpHeaderSize:decryptedLen])
+ } else if !sameBuffer {
+ copy(dst[srtcpHeaderSize:], encrypted[srtcpHeaderSize:])
+ }
+
+ return dst, err
}
-func (s *srtpCipherAesCmHmacSha1) generateSrtpAuthTag(buf []byte, roc uint32) ([]byte, error) {
+func (s *srtpCipherAesCmHmacSha1) generateSrtpAuthTag(buf []byte, roc uint32, rocInAuthTag bool) ([]byte, error) {
// https://tools.ietf.org/html/rfc3711#section-4.2
// In the case of SRTP, M SHALL consist of the Authenticated
// Portion of the packet (as specified in Figure 1) concatenated with
@@ -279,7 +337,13 @@ func (s *srtpCipherAesCmHmacSha1) generateSrtpAuthTag(buf []byte, roc uint32) ([
if err != nil {
return nil, err
}
- return s.srtpSessionAuth.Sum(nil)[0:authTagLen], nil
+
+ var authTag []byte
+ if rocInAuthTag {
+ authTag = append(authTag, rocRaw[:]...)
+ }
+
+ return s.srtpSessionAuth.Sum(authTag)[0:authTagLen], nil
}
func (s *srtpCipherAesCmHmacSha1) generateSrtcpAuthTag(buf []byte) ([]byte, error) {
@@ -311,21 +375,6 @@ func (s *srtpCipherAesCmHmacSha1) getRTCPIndex(in []byte) uint32 {
authTagLen, _ := s.AuthTagRTCPLen()
tailOffset := len(in) - (authTagLen + srtcpIndexSize + len(s.mki))
srtcpIndexBuffer := in[tailOffset : tailOffset+srtcpIndexSize]
+
return binary.BigEndian.Uint32(srtcpIndexBuffer) &^ (1 << 31)
}
-
-func (s *srtpCipherAesCmHmacSha1) getMKI(in []byte, rtp bool) []byte {
- mkiLen := len(s.mki)
- if mkiLen == 0 {
- return nil
- }
-
- var authTagLen int
- if rtp {
- authTagLen, _ = s.AuthTagRTPLen()
- } else {
- authTagLen, _ = s.AuthTagRTCPLen()
- }
- tailOffset := len(in) - (authTagLen + mkiLen)
- return in[tailOffset : tailOffset+mkiLen]
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtcp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtcp.go
index dc71c40f3..8fe407f64 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtcp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtcp.go
@@ -13,10 +13,10 @@ import (
"github.com/pion/transport/v3/packetio"
)
-// Limit the buffer size to 100KB
+// Limit the buffer size to 100KB.
const srtcpBufferSize = 100 * 1000
-// ReadStreamSRTCP handles decryption for a single RTCP SSRC
+// ReadStreamSRTCP handles decryption for a single RTCP SSRC.
type ReadStreamSRTCP struct {
mu sync.Mutex
@@ -40,12 +40,12 @@ func (r *ReadStreamSRTCP) write(buf []byte) (n int, err error) {
return n, err
}
-// Used by getOrCreateReadStream
+// Used by getOrCreateReadStream.
func newReadStreamSRTCP() readStream {
return &ReadStreamSRTCP{}
}
-// ReadRTCP reads and decrypts full RTCP packet and its header from the nextConn
+// ReadRTCP reads and decrypts full RTCP packet and its header from the nextConn.
func (r *ReadStreamSRTCP) ReadRTCP(buf []byte) (int, *rtcp.Header, error) {
n, err := r.Read(buf)
if err != nil {
@@ -61,7 +61,7 @@ func (r *ReadStreamSRTCP) ReadRTCP(buf []byte) (int, *rtcp.Header, error) {
return n, header, nil
}
-// Read reads and decrypts full RTCP packet from the nextConn
+// Read reads and decrypts full RTCP packet from the nextConn.
func (r *ReadStreamSRTCP) Read(buf []byte) (int, error) {
return r.buffer.Read(buf)
}
@@ -74,10 +74,11 @@ func (r *ReadStreamSRTCP) SetReadDeadline(t time.Time) error {
}); ok {
return b.SetReadDeadline(t)
}
+
return nil
}
-// Close removes the ReadStream from the session and cleans up any associated state
+// Close removes the ReadStream from the session and cleans up any associated state.
func (r *ReadStreamSRTCP) Close() error {
r.mu.Lock()
defer r.mu.Unlock()
@@ -96,6 +97,7 @@ func (r *ReadStreamSRTCP) Close() error {
}
r.session.removeReadStream(r.ssrc)
+
return nil
}
}
@@ -128,17 +130,17 @@ func (r *ReadStreamSRTCP) init(child streamSession, ssrc uint32) error {
return nil
}
-// GetSSRC returns the SSRC we are demuxing for
+// GetSSRC returns the SSRC we are demuxing for.
func (r *ReadStreamSRTCP) GetSSRC() uint32 {
return r.ssrc
}
-// WriteStreamSRTCP is stream for a single Session that is used to encrypt RTCP
+// WriteStreamSRTCP is stream for a single Session that is used to encrypt RTCP.
type WriteStreamSRTCP struct {
session *SessionSRTCP
}
-// WriteRTCP encrypts a RTCP header and its payload to the nextConn
+// WriteRTCP encrypts a RTCP header and its payload to the nextConn.
func (w *WriteStreamSRTCP) WriteRTCP(header *rtcp.Header, payload []byte) (int, error) {
headerRaw, err := header.Marshal()
if err != nil {
@@ -148,7 +150,7 @@ func (w *WriteStreamSRTCP) WriteRTCP(header *rtcp.Header, payload []byte) (int,
return w.session.write(append(headerRaw, payload...))
}
-// Write encrypts and writes a full RTCP packets to the nextConn
+// Write encrypts and writes a full RTCP packets to the nextConn.
func (w *WriteStreamSRTCP) Write(b []byte) (int, error) {
return w.session.write(b)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtp.go
index cad0a38c1..1b34266c1 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/stream_srtp.go
@@ -13,10 +13,10 @@ import (
"github.com/pion/transport/v3/packetio"
)
-// Limit the buffer size to 1MB
+// Limit the buffer size to 1MB.
const srtpBufferSize = 1000 * 1000
-// ReadStreamSRTP handles decryption for a single RTP SSRC
+// ReadStreamSRTP handles decryption for a single RTP SSRC.
type ReadStreamSRTP struct {
mu sync.Mutex
@@ -29,7 +29,7 @@ type ReadStreamSRTP struct {
buffer io.ReadWriteCloser
}
-// Used by getOrCreateReadStream
+// Used by getOrCreateReadStream.
func newReadStreamSRTP() readStream {
return &ReadStreamSRTP{}
}
@@ -74,12 +74,12 @@ func (r *ReadStreamSRTP) write(buf []byte) (n int, err error) {
return n, err
}
-// Read reads and decrypts full RTP packet from the nextConn
+// Read reads and decrypts full RTP packet from the nextConn.
func (r *ReadStreamSRTP) Read(buf []byte) (int, error) {
return r.buffer.Read(buf)
}
-// ReadRTP reads and decrypts full RTP packet and its header from the nextConn
+// ReadRTP reads and decrypts full RTP packet and its header from the nextConn.
func (r *ReadStreamSRTP) ReadRTP(buf []byte) (int, *rtp.Header, error) {
n, err := r.Read(buf)
if err != nil {
@@ -104,10 +104,11 @@ func (r *ReadStreamSRTP) SetReadDeadline(t time.Time) error {
}); ok {
return b.SetReadDeadline(t)
}
+
return nil
}
-// Close removes the ReadStream from the session and cleans up any associated state
+// Close removes the ReadStream from the session and cleans up any associated state.
func (r *ReadStreamSRTP) Close() error {
r.mu.Lock()
defer r.mu.Unlock()
@@ -126,26 +127,27 @@ func (r *ReadStreamSRTP) Close() error {
}
r.session.removeReadStream(r.ssrc)
+
return nil
}
}
-// GetSSRC returns the SSRC we are demuxing for
+// GetSSRC returns the SSRC we are demuxing for.
func (r *ReadStreamSRTP) GetSSRC() uint32 {
return r.ssrc
}
-// WriteStreamSRTP is stream for a single Session that is used to encrypt RTP
+// WriteStreamSRTP is stream for a single Session that is used to encrypt RTP.
type WriteStreamSRTP struct {
session *SessionSRTP
}
-// WriteRTP encrypts a RTP packet and writes to the connection
+// WriteRTP encrypts a RTP packet and writes to the connection.
func (w *WriteStreamSRTP) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
return w.session.writeRTP(header, payload)
}
-// Write encrypts and writes a full RTP packets to the nextConn
+// Write encrypts and writes a full RTP packets to the nextConn.
func (w *WriteStreamSRTP) Write(b []byte) (int, error) {
return w.session.write(b)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/util.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/util.go
index 792175d96..84116014e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/util.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/srtp/v3/util.go
@@ -3,9 +3,11 @@
package srtp
-import "bytes"
+import (
+ "unsafe"
+)
-// Grow the buffer size to the given number of bytes.
+// growBufferSize grows the buffer size to the given number of bytes.
func growBufferSize(buf []byte, size int) []byte {
if size <= cap(buf) {
return buf[:size]
@@ -13,24 +15,25 @@ func growBufferSize(buf []byte, size int) []byte {
buf2 := make([]byte, size)
copy(buf2, buf)
+
return buf2
}
-// Check if buffers match, if not allocate a new buffer and return it
-func allocateIfMismatch(dst, src []byte) []byte {
- if dst == nil {
- dst = make([]byte, len(src))
- copy(dst, src)
- } else if !bytes.Equal(dst, src) { // bytes.Equal returns on ref equality, no optimization needed
- extraNeeded := len(src) - len(dst)
- if extraNeeded > 0 {
- dst = append(dst, make([]byte, extraNeeded)...)
- } else if extraNeeded < 0 {
- dst = dst[:len(dst)+extraNeeded]
- }
-
- copy(dst, src)
+// isSameBuffer returns true if slices a and b share the same underlying buffer.
+func isSameBuffer(a, b []byte) bool {
+ // If both are nil, they are technically the same (no buffer)
+ if a == nil && b == nil {
+ return true
}
- return dst
+ // If either is nil, or both have 0 capacity, they can't share backing buffer
+ if cap(a) == 0 || cap(b) == 0 {
+ return false
+ }
+
+ // Create a slice of length 1 from each if possible
+ aPtr := unsafe.Pointer(&a[:1][0]) // nolint:gosec
+ bPtr := unsafe.Pointer(&b[:1][0]) // nolint:gosec
+
+ return aPtr == bPtr
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/.golangci.yml
index e06de4d3c..120faf29b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/.golangci.yml
@@ -1,6 +1,9 @@
# SPDX-FileCopyrightText: 2023 The Pion community
# SPDX-License-Identifier: MIT
+run:
+ timeout: 5m
+
linters-settings:
govet:
enable:
@@ -16,23 +19,42 @@ linters-settings:
recommendations:
- errors
forbidigo:
+ analyze-types: true
forbid:
- ^fmt.Print(f|ln)?$
- ^log.(Panic|Fatal|Print)(f|ln)?$
- ^os.Exit$
- ^panic$
- ^print(ln)?$
+ - p: ^testing.T.(Error|Errorf|Fatal|Fatalf|Fail|FailNow)$
+ pkg: ^testing$
+ msg: "use testify/assert instead"
+ 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`.
@@ -43,18 +65,17 @@ linters:
- forcetypeassert # finds forced type assertions
- 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
- - goerr113 # 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
@@ -62,9 +83,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
@@ -72,31 +99,22 @@ 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
- - exhaustivestruct # Checks if all struct's fields are initialized
- 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.
- - ifshort # Checks that your code uses short syntax for if-statements whenever possible
+ - 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
- - maligned # Tool to detect Go structs that would take less memory if their fields were sorted
- - 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 +122,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!
@@ -114,9 +131,12 @@ issues:
exclude-dirs-use-default: false
exclude-rules:
# Allow complex tests and examples, better to be self contained
- - path: (examples|main\.go|_test\.go)
+ - path: (examples|main\.go)
linters:
+ - gocognit
- forbidigo
+ - path: _test\.go
+ linters:
- gocognit
# Allow forbidden identifiers in CLI commands
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/README.md b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/README.md
index a571c0ba9..9c8d7038e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/README.md
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/README.md
@@ -7,13 +7,13 @@
A toolkit for building TURN clients and servers in Go
-
+
-
+
-
+
@@ -79,9 +79,9 @@ Yes.
The library is used as a part of our WebRTC implementation. Please refer to that [roadmap](https://github.com/pion/webrtc/issues/9) to track our major milestones.
### Community
-Pion has an active community on the [Slack](https://pion.ly/slack).
+Pion has an active community on the [Discord](https://discord.gg/PngbdqpFbt).
-Follow the [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
+Follow the [Pion Bluesky](https://bsky.app/profile/pion.ly) or [Pion Twitter](https://twitter.com/_pion) for project updates and important WebRTC news.
We are always looking to support **your projects**. Please reach out if you have something to build!
If you need commercial support or don't want to use public methods you can contact us at [team@pion.ly](mailto:team@pion.ly)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/client.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/client.go
index 6e38ae109..68d40c866 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/client.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/client.go
@@ -49,7 +49,7 @@ type ClientConfig struct {
LoggerFactory logging.LoggerFactory
}
-// Client is a STUN server client
+// Client is a STUN server client.
type Client struct {
conn net.PacketConn // Read-only
net transport.Net // Read-only
@@ -72,7 +72,8 @@ type Client struct {
log logging.LeveledLogger // Read-only
}
-// NewClient returns a new Client instance. listeningAddress is the address and port to listen on, default "0.0.0.0:0"
+// NewClient returns a new Client instance. listeningAddress is the address and port to listen on,
+// default "0.0.0.0:0".
func NewClient(config *ClientConfig) (*Client, error) {
loggerFactory := config.LoggerFactory
if loggerFactory == nil {
@@ -119,7 +120,7 @@ func NewClient(config *ClientConfig) (*Client, error) {
log.Debugf("Resolved TURN server %s to %s", config.TURNServerAddr, turnServ)
}
- c := &Client{
+ client := &Client{
conn: config.Conn,
stunServerAddr: stunServ,
turnServerAddr: turnServ,
@@ -133,25 +134,25 @@ func NewClient(config *ClientConfig) (*Client, error) {
log: log,
}
- return c, nil
+ return client, nil
}
-// TURNServerAddr return the TURN server address
+// TURNServerAddr return the TURN server address.
func (c *Client) TURNServerAddr() net.Addr {
return c.turnServerAddr
}
-// STUNServerAddr return the STUN server address
+// STUNServerAddr return the STUN server address.
func (c *Client) STUNServerAddr() net.Addr {
return c.stunServerAddr
}
-// Username returns username
+// Username returns username.
func (c *Client) Username() stun.Username {
return c.username
}
-// Realm return realm
+// Realm return realm.
func (c *Client) Realm() stun.Realm {
return c.realm
}
@@ -175,12 +176,14 @@ func (c *Client) Listen() error {
n, from, err := c.conn.ReadFrom(buf)
if err != nil {
c.log.Debugf("Failed to read: %s. Exiting loop", err)
+
break
}
_, err = c.HandleInbound(buf[:n], from)
if err != nil {
c.log.Debugf("Failed to handle inbound message: %s. Exiting loop", err)
+
break
}
}
@@ -191,7 +194,7 @@ func (c *Client) Listen() error {
return nil
}
-// Close closes this client
+// Close closes this client.
func (c *Client) Close() {
c.mutexTrMap.Lock()
defer c.mutexTrMap.Unlock()
@@ -201,7 +204,7 @@ func (c *Client) Close() {
// TransactionID & Base64: https://play.golang.org/p/EEgmJDI971P
-// SendBindingRequestTo sends a new STUN request to the given transport address
+// SendBindingRequestTo sends a new STUN request to the given transport address.
func (c *Client) SendBindingRequestTo(to net.Addr) (net.Addr, error) {
attrs := []stun.Setter{stun.TransactionID, stun.BindingRequest}
if len(c.software) > 0 {
@@ -228,15 +231,21 @@ func (c *Client) SendBindingRequestTo(to net.Addr) (net.Addr, error) {
}, nil
}
-// SendBindingRequest sends a new STUN request to the STUN server
+// SendBindingRequest sends a new STUN request to the STUN server.
func (c *Client) SendBindingRequest() (net.Addr, error) {
if c.stunServerAddr == nil {
return nil, errSTUNServerAddressNotSet
}
+
return c.SendBindingRequestTo(c.stunServerAddr)
}
-func (c *Client) sendAllocateRequest(protocol proto.Protocol) (proto.RelayedAddress, proto.Lifetime, stun.Nonce, error) {
+func (c *Client) sendAllocateRequest(protocol proto.Protocol) ( //nolint:cyclop
+ proto.RelayedAddress,
+ proto.Lifetime,
+ stun.Nonce,
+ error,
+) {
var relayed proto.RelayedAddress
var lifetime proto.Lifetime
var nonce stun.Nonce
@@ -295,6 +304,7 @@ func (c *Client) sendAllocateRequest(protocol proto.Protocol) (proto.RelayedAddr
if err = code.GetFrom(res); err == nil {
return relayed, lifetime, nonce, fmt.Errorf("%s (error %s)", res.Type, code) //nolint:goerr113
}
+
return relayed, lifetime, nonce, fmt.Errorf("%s", res.Type) //nolint:goerr113
}
@@ -307,10 +317,11 @@ func (c *Client) sendAllocateRequest(protocol proto.Protocol) (proto.RelayedAddr
if err := lifetime.GetFrom(res); err != nil {
return relayed, lifetime, nonce, err
}
+
return relayed, lifetime, nonce, nil
}
-// Allocate sends a TURN allocation request to the given transport address
+// Allocate sends a TURN allocation request to the given transport address.
func (c *Client) Allocate() (net.PacketConn, error) {
if err := c.allocTryLock.Lock(); err != nil {
return nil, fmt.Errorf("%w: %s", errOneAllocateOnly, err.Error())
@@ -403,10 +414,11 @@ func (c *Client) CreatePermission(addrs ...net.Addr) error {
return err
}
}
+
return nil
}
-// PerformTransaction performs STUN transaction
+// PerformTransaction performs STUN transaction.
func (c *Client) PerformTransaction(msg *stun.Message, to net.Addr, ignoreResult bool) (client.TransactionResult,
error,
) {
@@ -442,11 +454,12 @@ func (c *Client) PerformTransaction(msg *stun.Message, to net.Addr, ignoreResult
if res.Err != nil {
return res, res.Err
}
+
return res, nil
}
// OnDeallocated is called when de-allocation of relay address has been complete.
-// (Called by UDPConn)
+// (Called by UDPConn).
func (c *Client) OnDeallocated(net.Addr) {
c.setRelayedUDPConn(nil)
c.setTCPAllocation(nil)
@@ -494,7 +507,7 @@ func (c *Client) HandleInbound(data []byte, from net.Addr) (bool, error) {
return false, nil
}
-func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
+func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error { //nolint:cyclop
raw := make([]byte, len(data))
copy(raw, data)
@@ -507,7 +520,7 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
return fmt.Errorf("%w : %s", errUnexpectedSTUNRequestMessage, msg.String())
}
- if msg.Type.Class == stun.ClassIndication {
+ if msg.Type.Class == stun.ClassIndication { // nolint:nestif
switch msg.Type.Method {
case stun.MethodData:
var peerAddr proto.PeerAddress
@@ -529,6 +542,7 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
relayedConn := c.relayedUDPConn()
if relayedConn == nil {
c.log.Debug("No relayed conn allocated")
+
return nil // Silently discard
}
relayedConn.HandleInbound(data, from)
@@ -553,6 +567,7 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
allocation := c.getTCPAllocation()
if allocation == nil {
c.log.Debug("No TCP allocation exists")
+
return nil // Silently discard
}
@@ -560,6 +575,7 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
default:
c.log.Debug("Received unsupported STUN method")
}
+
return nil
}
@@ -576,6 +592,7 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
c.mutexTrMap.Unlock()
// Silently discard
c.log.Debugf("No transaction for %s", msg)
+
return nil
}
@@ -607,6 +624,7 @@ func (c *Client) handleChannelData(data []byte) error {
relayedConn := c.relayedUDPConn()
if relayedConn == nil {
c.log.Debug("No relayed conn allocated")
+
return nil // Silently discard
}
@@ -618,6 +636,7 @@ func (c *Client) handleChannelData(data []byte) error {
c.log.Tracef("Channel data received from %s (ch=%d)", addr.String(), int(chData.Number))
relayedConn.HandleInbound(chData.Data, addr)
+
return nil
}
@@ -638,11 +657,12 @@ func (c *Client) onRtxTimeout(trKey string, nRtx int) {
}) {
c.log.Debug("No listener for transaction")
}
+
return
}
c.log.Tracef("Retransmitting transaction %s to %s (nRtx=%d)",
- trKey, tr.To.String(), nRtx)
+ trKey, tr.To, nRtx)
_, err := c.conn.WriteTo(tr.Raw, tr.To)
if err != nil {
c.trMap.Delete(trKey)
@@ -651,6 +671,7 @@ func (c *Client) onRtxTimeout(trKey string, nRtx int) {
}) {
c.log.Debug("No listener for transaction")
}
+
return
}
tr.StartRtxTimer(c.onRtxTimeout)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation.go
index 5b5ff369b..9e2d53521 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation.go
@@ -22,7 +22,7 @@ type allocationResponse struct {
}
// Allocation is tied to a FiveTuple and relays traffic
-// use CreateAllocation and GetAllocation to operate
+// use CreateAllocation and GetAllocation to operate.
type Allocation struct {
RelayAddr net.Addr
Protocol Protocol
@@ -55,7 +55,7 @@ func NewAllocation(turnSocket net.PacketConn, fiveTuple *FiveTuple, log logging.
}
}
-// GetPermission gets the Permission from the allocation
+// GetPermission gets the Permission from the allocation.
func (a *Allocation) GetPermission(addr net.Addr) *Permission {
a.permissionsLock.RLock()
defer a.permissionsLock.RUnlock()
@@ -63,9 +63,9 @@ func (a *Allocation) GetPermission(addr net.Addr) *Permission {
return a.permissions[ipnet.FingerprintAddr(addr)]
}
-// AddPermission adds a new permission to the allocation
-func (a *Allocation) AddPermission(p *Permission) {
- fingerprint := ipnet.FingerprintAddr(p.Addr)
+// AddPermission adds a new permission to the allocation.
+func (a *Allocation) AddPermission(perms *Permission) {
+ fingerprint := ipnet.FingerprintAddr(perms.Addr)
a.permissionsLock.RLock()
existedPermission, ok := a.permissions[fingerprint]
@@ -73,18 +73,19 @@ func (a *Allocation) AddPermission(p *Permission) {
if ok {
existedPermission.refresh(permissionTimeout)
+
return
}
- p.allocation = a
+ perms.allocation = a
a.permissionsLock.Lock()
- a.permissions[fingerprint] = p
+ a.permissions[fingerprint] = perms
a.permissionsLock.Unlock()
- p.start(permissionTimeout)
+ perms.start(permissionTimeout)
}
-// RemovePermission removes the net.Addr's fingerprint from the allocation's permissions
+// RemovePermission removes the net.Addr's fingerprint from the allocation's permissions.
func (a *Allocation) RemovePermission(addr net.Addr) {
a.permissionsLock.Lock()
defer a.permissionsLock.Unlock()
@@ -92,13 +93,13 @@ func (a *Allocation) RemovePermission(addr net.Addr) {
}
// AddChannelBind adds a new ChannelBind to the allocation, it also updates the
-// permissions needed for this ChannelBind
-func (a *Allocation) AddChannelBind(c *ChannelBind, lifetime time.Duration) error {
+// permissions needed for this ChannelBind.
+func (a *Allocation) AddChannelBind(chanBind *ChannelBind, lifetime time.Duration) error {
// Check that this channel id isn't bound to another transport address, and
// that this transport address isn't bound to another channel number.
- channelByNumber := a.GetChannelByNumber(c.Number)
+ channelByNumber := a.GetChannelByNumber(chanBind.Number)
- if channelByNumber != a.GetChannelByAddr(c.Peer) {
+ if channelByNumber != a.GetChannelByAddr(chanBind.Peer) {
return errSameChannelDifferentPeer
}
@@ -107,12 +108,12 @@ func (a *Allocation) AddChannelBind(c *ChannelBind, lifetime time.Duration) erro
a.channelBindingsLock.Lock()
defer a.channelBindingsLock.Unlock()
- c.allocation = a
- a.channelBindings = append(a.channelBindings, c)
- c.start(lifetime)
+ chanBind.allocation = a
+ a.channelBindings = append(a.channelBindings, chanBind)
+ chanBind.start(lifetime)
// Channel binds also refresh permissions.
- a.AddPermission(NewPermission(c.Peer, a.log))
+ a.AddPermission(NewPermission(chanBind.Peer, a.log))
} else {
channelByNumber.refresh(lifetime)
@@ -123,7 +124,7 @@ func (a *Allocation) AddChannelBind(c *ChannelBind, lifetime time.Duration) erro
return nil
}
-// RemoveChannelBind removes the ChannelBind from this allocation by id
+// RemoveChannelBind removes the ChannelBind from this allocation by id.
func (a *Allocation) RemoveChannelBind(number proto.ChannelNumber) bool {
a.channelBindingsLock.Lock()
defer a.channelBindingsLock.Unlock()
@@ -131,6 +132,7 @@ func (a *Allocation) RemoveChannelBind(number proto.ChannelNumber) bool {
for i := len(a.channelBindings) - 1; i >= 0; i-- {
if a.channelBindings[i].Number == number {
a.channelBindings = append(a.channelBindings[:i], a.channelBindings[i+1:]...)
+
return true
}
}
@@ -138,7 +140,7 @@ func (a *Allocation) RemoveChannelBind(number proto.ChannelNumber) bool {
return false
}
-// GetChannelByNumber gets the ChannelBind from this allocation by id
+// GetChannelByNumber gets the ChannelBind from this allocation by id.
func (a *Allocation) GetChannelByNumber(number proto.ChannelNumber) *ChannelBind {
a.channelBindingsLock.RLock()
defer a.channelBindingsLock.RUnlock()
@@ -147,10 +149,11 @@ func (a *Allocation) GetChannelByNumber(number proto.ChannelNumber) *ChannelBind
return cb
}
}
+
return nil
}
-// GetChannelByAddr gets the ChannelBind from this allocation by net.Addr
+// GetChannelByAddr gets the ChannelBind from this allocation by net.Addr.
func (a *Allocation) GetChannelByAddr(addr net.Addr) *ChannelBind {
a.channelBindingsLock.RLock()
defer a.channelBindingsLock.RUnlock()
@@ -159,17 +162,18 @@ func (a *Allocation) GetChannelByAddr(addr net.Addr) *ChannelBind {
return cb
}
}
+
return nil
}
-// Refresh updates the allocations lifetime
+// Refresh updates the allocations lifetime.
func (a *Allocation) Refresh(lifetime time.Duration) {
if !a.lifetimeTimer.Reset(lifetime) {
a.log.Errorf("Failed to reset allocation timer for %v", a.fiveTuple)
}
}
-// SetResponseCache cache allocation response for retransmit allocation request
+// SetResponseCache cache allocation response for retransmit allocation request.
func (a *Allocation) SetResponseCache(transactionID [stun.TransactionIDSize]byte, attrs []stun.Setter) {
a.responseCache.Store(&allocationResponse{
transactionID: transactionID,
@@ -177,15 +181,16 @@ func (a *Allocation) SetResponseCache(transactionID [stun.TransactionIDSize]byte
})
}
-// GetResponseCache return response cache for retransmit allocation request
+// GetResponseCache return response cache for retransmit allocation request.
func (a *Allocation) GetResponseCache() (id [stun.TransactionIDSize]byte, attrs []stun.Setter) {
if res, ok := a.responseCache.Load().(*allocationResponse); ok && res != nil {
id, attrs = res.transactionID, res.responseAttrs
}
+
return
}
-// Close closes the allocation
+// Close closes the allocation.
func (a *Allocation) Close() error {
select {
case <-a.closed:
@@ -233,13 +238,14 @@ func (a *Allocation) Close() error {
const rtpMTU = 1600
-func (a *Allocation) packetHandler(m *Manager) {
+func (a *Allocation) packetHandler(manager *Manager) {
buffer := make([]byte, rtpMTU)
for {
n, srcAddr, err := a.RelaySocket.ReadFrom(buffer)
if err != nil {
- m.DeleteAllocation(a.fiveTuple)
+ manager.DeleteAllocation(a.fiveTuple)
+
return
}
@@ -248,7 +254,7 @@ func (a *Allocation) packetHandler(m *Manager) {
n,
srcAddr)
- if channel := a.GetChannelByAddr(srcAddr); channel != nil {
+ if channel := a.GetChannelByAddr(srcAddr); channel != nil { // nolint:nestif
channelData := &proto.ChannelData{
Data: buffer[:n],
Number: channel.Number,
@@ -262,15 +268,22 @@ func (a *Allocation) packetHandler(m *Manager) {
udpAddr, ok := srcAddr.(*net.UDPAddr)
if !ok {
a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
+
return
}
peerAddressAttr := proto.PeerAddress{IP: udpAddr.IP, Port: udpAddr.Port}
dataAttr := proto.Data(buffer[:n])
- msg, err := stun.Build(stun.TransactionID, stun.NewType(stun.MethodData, stun.ClassIndication), peerAddressAttr, dataAttr)
+ msg, err := stun.Build(
+ stun.TransactionID,
+ stun.NewType(stun.MethodData, stun.ClassIndication),
+ peerAddressAttr,
+ dataAttr,
+ )
if err != nil {
a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
+
return
}
a.log.Debugf("Relaying message from %s to client at %s",
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation_manager.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation_manager.go
index 2b7659212..a3b011f4e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation_manager.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/allocation_manager.go
@@ -25,7 +25,7 @@ type reservation struct {
port int
}
-// Manager is used to hold active allocations
+// Manager is used to hold active allocations.
type Manager struct {
lock sync.RWMutex
log logging.LeveledLogger
@@ -58,21 +58,23 @@ func NewManager(config ManagerConfig) (*Manager, error) {
}, nil
}
-// GetAllocation fetches the allocation matching the passed FiveTuple
+// GetAllocation fetches the allocation matching the passed FiveTuple.
func (m *Manager) GetAllocation(fiveTuple *FiveTuple) *Allocation {
m.lock.RLock()
defer m.lock.RUnlock()
+
return m.allocations[fiveTuple.Fingerprint()]
}
-// AllocationCount returns the number of existing allocations
+// AllocationCount returns the number of existing allocations.
func (m *Manager) AllocationCount() int {
m.lock.RLock()
defer m.lock.RUnlock()
+
return len(m.allocations)
}
-// Close closes the manager and closes all allocations it manages
+// Close closes the manager and closes all allocations it manages.
func (m *Manager) Close() error {
m.lock.Lock()
defer m.lock.Unlock()
@@ -82,11 +84,17 @@ func (m *Manager) Close() error {
return err
}
}
+
return nil
}
-// CreateAllocation creates a new allocation and starts relaying
-func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketConn, requestedPort int, lifetime time.Duration) (*Allocation, error) {
+// CreateAllocation creates a new allocation and starts relaying.
+func (m *Manager) CreateAllocation(
+ fiveTuple *FiveTuple,
+ turnSocket net.PacketConn,
+ requestedPort int,
+ lifetime time.Duration,
+) (*Allocation, error) {
switch {
case fiveTuple == nil:
return nil, errNilFiveTuple
@@ -100,34 +108,35 @@ func (m *Manager) CreateAllocation(fiveTuple *FiveTuple, turnSocket net.PacketCo
return nil, errLifetimeZero
}
- if a := m.GetAllocation(fiveTuple); a != nil {
+ if alloc := m.GetAllocation(fiveTuple); alloc != nil {
return nil, fmt.Errorf("%w: %v", errDupeFiveTuple, fiveTuple)
}
- a := NewAllocation(turnSocket, fiveTuple, m.log)
+ alloc := NewAllocation(turnSocket, fiveTuple, m.log)
conn, relayAddr, err := m.allocatePacketConn("udp4", requestedPort)
if err != nil {
return nil, err
}
- a.RelaySocket = conn
- a.RelayAddr = relayAddr
+ alloc.RelaySocket = conn
+ alloc.RelayAddr = relayAddr
- m.log.Debugf("Listening on relay address: %s", a.RelayAddr)
+ m.log.Debugf("Listening on relay address: %s", alloc.RelayAddr)
- a.lifetimeTimer = time.AfterFunc(lifetime, func() {
- m.DeleteAllocation(a.fiveTuple)
+ alloc.lifetimeTimer = time.AfterFunc(lifetime, func() {
+ m.DeleteAllocation(alloc.fiveTuple)
})
m.lock.Lock()
- m.allocations[fiveTuple.Fingerprint()] = a
+ m.allocations[fiveTuple.Fingerprint()] = alloc
m.lock.Unlock()
- go a.packetHandler(m)
- return a, nil
+ go alloc.packetHandler(m)
+
+ return alloc, nil
}
-// DeleteAllocation removes an allocation
+// DeleteAllocation removes an allocation.
func (m *Manager) DeleteAllocation(fiveTuple *FiveTuple) {
fingerprint := fiveTuple.Fingerprint()
@@ -145,7 +154,7 @@ func (m *Manager) DeleteAllocation(fiveTuple *FiveTuple) {
}
}
-// CreateReservation stores the reservation for the token+port
+// CreateReservation stores the reservation for the token+port.
func (m *Manager) CreateReservation(reservationToken string, port int) {
time.AfterFunc(30*time.Second, func() {
m.lock.Lock()
@@ -153,6 +162,7 @@ func (m *Manager) CreateReservation(reservationToken string, port int) {
for i := len(m.reservations) - 1; i >= 0; i-- {
if m.reservations[i].token == reservationToken {
m.reservations = append(m.reservations[:i], m.reservations[i+1:]...)
+
return
}
}
@@ -166,7 +176,7 @@ func (m *Manager) CreateReservation(reservationToken string, port int) {
m.lock.Unlock()
}
-// GetReservation returns the port for a given reservation if it exists
+// GetReservation returns the port for a given reservation if it exists.
func (m *Manager) GetReservation(reservationToken string) (int, bool) {
m.lock.RLock()
defer m.lock.RUnlock()
@@ -176,10 +186,11 @@ func (m *Manager) GetReservation(reservationToken string) (int, bool) {
return r.port, true
}
}
+
return 0, false
}
-// GetRandomEvenPort returns a random un-allocated udp4 port
+// GetRandomEvenPort returns a random un-allocated udp4 port.
func (m *Manager) GetRandomEvenPort() (int, error) {
for i := 0; i < 128; i++ {
conn, addr, err := m.allocatePacketConn("udp4", 0)
@@ -199,11 +210,12 @@ func (m *Manager) GetRandomEvenPort() (int, error) {
return udpAddr.Port, nil
}
}
+
return 0, errFailedToAllocateEvenPort
}
// GrantPermission handles permission requests by calling the permission handler callback
-// associated with the TURN server listener socket
+// associated with the TURN server listener socket.
func (m *Manager) GrantPermission(sourceAddr net.Addr, peerIP net.IP) error {
// No permission handler: open
if m.permissionHandler == nil {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/channel_bind.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/channel_bind.go
index 19b184317..6ad9b46f0 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/channel_bind.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/channel_bind.go
@@ -22,7 +22,7 @@ type ChannelBind struct {
log logging.LeveledLogger
}
-// NewChannelBind creates a new ChannelBind
+// NewChannelBind creates a new ChannelBind.
func NewChannelBind(number proto.ChannelNumber, peer net.Addr, log logging.LeveledLogger) *ChannelBind {
return &ChannelBind{
Number: number,
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/five_tuple.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/five_tuple.go
index 6d812caf7..14761611d 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/five_tuple.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/five_tuple.go
@@ -7,10 +7,10 @@ import (
"net"
)
-// Protocol is an enum for relay protocol
+// Protocol is an enum for relay protocol.
type Protocol uint8
-// Network protocols for relay
+// Network protocols for relay.
const (
UDP Protocol = iota
TCP
@@ -27,19 +27,19 @@ type FiveTuple struct {
SrcAddr, DstAddr net.Addr
}
-// Equal asserts if two FiveTuples are equal
+// Equal asserts if two FiveTuples are equal.
func (f *FiveTuple) Equal(b *FiveTuple) bool {
return f.Fingerprint() == b.Fingerprint()
}
-// FiveTupleFingerprint is a comparable representation of a FiveTuple
+// FiveTupleFingerprint is a comparable representation of a FiveTuple.
type FiveTupleFingerprint struct {
srcIP, dstIP [16]byte
srcPort, dstPort uint16
protocol Protocol
}
-// Fingerprint is the identity of a FiveTuple
+// Fingerprint is the identity of a FiveTuple.
func (f *FiveTuple) Fingerprint() (fp FiveTupleFingerprint) {
srcIP, srcPort := netAddrIPAndPort(f.SrcAddr)
copy(fp.srcIP[:], srcIP)
@@ -48,15 +48,16 @@ func (f *FiveTuple) Fingerprint() (fp FiveTupleFingerprint) {
copy(fp.dstIP[:], dstIP)
fp.dstPort = dstPort
fp.protocol = f.Protocol
+
return
}
func netAddrIPAndPort(addr net.Addr) (net.IP, uint16) {
switch a := addr.(type) {
case *net.UDPAddr:
- return a.IP.To16(), uint16(a.Port)
+ return a.IP.To16(), uint16(a.Port) // nolint:gosec // G115
case *net.TCPAddr:
- return a.IP.To16(), uint16(a.Port)
+ return a.IP.To16(), uint16(a.Port) // nolint:gosec // G115
default:
return nil, 0
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/permission.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/permission.go
index a774f2ceb..7b02adc35 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/permission.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/allocation/permission.go
@@ -22,7 +22,7 @@ type Permission struct {
log logging.LeveledLogger
}
-// NewPermission create a new Permission
+// NewPermission create a new Permission.
func NewPermission(addr net.Addr, log logging.LeveledLogger) *Permission {
return &Permission{
Addr: addr,
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/allocation.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/allocation.go
index a7f746360..ed64eb879 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/allocation.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/allocation.go
@@ -16,7 +16,7 @@ import (
"github.com/pion/turn/v4/internal/proto"
)
-// AllocationConfig is a set of configuration params use by NewUDPConn and NewTCPAllocation
+// AllocationConfig is a set of configuration params use by NewUDPConn and NewTCPAllocation.
type AllocationConfig struct {
Client Client
RelayedAddr net.Addr
@@ -82,6 +82,7 @@ func (a *allocation) refreshAllocation(lifetime time.Duration, dontWait bool) er
if dontWait {
a.log.Debug("Refresh request sent")
+
return nil
}
@@ -93,10 +94,13 @@ func (a *allocation) refreshAllocation(lifetime time.Duration, dontWait bool) er
if err = code.GetFrom(res); err == nil {
if code.Code == stun.CodeStaleNonce {
a.setNonceFromMsg(res)
+
return errTryAgain
}
+
return err
}
+
return fmt.Errorf("%s", res.Type) //nolint:goerr113
}
@@ -108,6 +112,7 @@ func (a *allocation) refreshAllocation(lifetime time.Duration, dontWait bool) er
a.setLifetime(updatedLifetime.Duration)
a.log.Debugf("Updated lifetime: %d seconds", int(a.lifetime().Seconds()))
+
return nil
}
@@ -115,6 +120,7 @@ func (a *allocation) refreshPermissions() error {
addrs := a.permMap.addrs()
if len(addrs) == 0 {
a.log.Debug("No permission to refresh")
+
return nil
}
if err := a.CreatePermissions(addrs...); err != nil {
@@ -122,9 +128,11 @@ func (a *allocation) refreshPermissions() error {
return errTryAgain
}
a.log.Errorf("Fail to refresh permissions: %s", err)
+
return err
}
a.log.Debug("Refresh permissions successful")
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/binding.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/binding.go
index a0217476e..1203cceb4 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/binding.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/binding.go
@@ -61,7 +61,7 @@ func (b *binding) refreshedAt() time.Time {
return b._refreshedAt
}
-// Thread-safe binding map
+// Thread-safe binding map.
type bindingManager struct {
chanMap map[uint16]*binding
addrMap map[string]*binding
@@ -84,6 +84,7 @@ func (mgr *bindingManager) assignChannelNumber() uint16 {
} else {
mgr.next++
}
+
return n
}
@@ -100,6 +101,7 @@ func (mgr *bindingManager) create(addr net.Addr) *binding {
mgr.chanMap[b.number] = b
mgr.addrMap[b.addr.String()] = b
+
return b
}
@@ -108,6 +110,7 @@ func (mgr *bindingManager) findByAddr(addr net.Addr) (*binding, bool) {
defer mgr.mutex.RUnlock()
b, ok := mgr.addrMap[addr.String()]
+
return b, ok
}
@@ -116,6 +119,7 @@ func (mgr *bindingManager) findByNumber(number uint16) (*binding, bool) {
defer mgr.mutex.RUnlock()
b, ok := mgr.chanMap[number]
+
return b, ok
}
@@ -130,6 +134,7 @@ func (mgr *bindingManager) deleteByAddr(addr net.Addr) bool {
delete(mgr.addrMap, addr.String())
delete(mgr.chanMap, b.number)
+
return true
}
@@ -144,6 +149,7 @@ func (mgr *bindingManager) deleteByNumber(number uint16) bool {
delete(mgr.addrMap, b.addr.String())
delete(mgr.chanMap, number)
+
return true
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/client.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/client.go
index 10b49a284..45041c904 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/client.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/client.go
@@ -10,7 +10,7 @@ import (
"github.com/pion/stun/v3"
)
-// Client is an interface for the public turn.Client in order to break cyclic dependencies
+// Client is an interface for the public turn.Client in order to break cyclic dependencies.
type Client interface {
WriteTo(data []byte, to net.Addr) (int, error)
PerformTransaction(msg *stun.Message, to net.Addr, dontWait bool) (TransactionResult, error)
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/periodic_timer.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/periodic_timer.go
index 5660bc45e..9e949129f 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/periodic_timer.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/periodic_timer.go
@@ -8,10 +8,10 @@ import (
"time"
)
-// PeriodicTimerTimeoutHandler is a handler called on timeout
+// PeriodicTimerTimeoutHandler is a handler called on timeout.
type PeriodicTimerTimeoutHandler func(timerID int)
-// PeriodicTimer is a periodic timer
+// PeriodicTimer is a periodic timer.
type PeriodicTimer struct {
id int
interval time.Duration
@@ -20,7 +20,7 @@ type PeriodicTimer struct {
mutex sync.RWMutex
}
-// NewPeriodicTimer create a new timer
+// NewPeriodicTimer create a new timer.
func NewPeriodicTimer(id int, timeoutHandler PeriodicTimerTimeoutHandler, interval time.Duration) *PeriodicTimer {
return &PeriodicTimer{
id: id,
@@ -76,7 +76,7 @@ func (t *PeriodicTimer) Stop() {
}
// IsRunning tests if the timer is running.
-// Debug purpose only
+// Debug purpose only.
func (t *PeriodicTimer) IsRunning() bool {
t.mutex.RLock()
defer t.mutex.RUnlock()
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/permission.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/permission.go
index 0436e4ea6..d6708d861 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/permission.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/permission.go
@@ -32,7 +32,7 @@ func (p *permission) state() permState {
return permState(atomic.LoadInt32((*int32)(&p.st)))
}
-// Thread-safe permission map
+// Thread-safe permission map.
type permissionMap struct {
permMap map[string]*permission
mutex sync.RWMutex
@@ -43,6 +43,7 @@ func (m *permissionMap) insert(addr net.Addr, p *permission) bool {
defer m.mutex.Unlock()
p.addr = addr
m.permMap[ipnet.FingerprintAddr(addr)] = p
+
return true
}
@@ -50,6 +51,7 @@ func (m *permissionMap) find(addr net.Addr) (*permission, bool) {
m.mutex.RLock()
defer m.mutex.RUnlock()
p, ok := m.permMap[ipnet.FingerprintAddr(addr)]
+
return p, ok
}
@@ -67,6 +69,7 @@ func (m *permissionMap) addrs() []net.Addr {
for _, p := range m.permMap {
addrs = append(addrs, p.addr)
}
+
return addrs
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_alloc.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_alloc.go
index 82948387c..5b72fe801 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_alloc.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_alloc.go
@@ -34,9 +34,9 @@ type TCPAllocation struct {
allocation
}
-// NewTCPAllocation creates a new instance of TCPConn
+// NewTCPAllocation creates a new instance of TCPConn.
func NewTCPAllocation(config *AllocationConfig) *TCPAllocation {
- a := &TCPAllocation{
+ alloc := &TCPAllocation{
connAttemptCh: make(chan *connectionAttempt, 10),
acceptTimer: time.NewTimer(time.Duration(math.MaxInt64)),
allocation: allocation{
@@ -54,31 +54,31 @@ func NewTCPAllocation(config *AllocationConfig) *TCPAllocation {
},
}
- a.log.Debugf("Initial lifetime: %d seconds", int(a.lifetime().Seconds()))
+ alloc.log.Debugf("Initial lifetime: %d seconds", int(alloc.lifetime().Seconds()))
- a.refreshAllocTimer = NewPeriodicTimer(
+ alloc.refreshAllocTimer = NewPeriodicTimer(
timerIDRefreshAlloc,
- a.onRefreshTimers,
- a.lifetime()/2,
+ alloc.onRefreshTimers,
+ alloc.lifetime()/2,
)
- a.refreshPermsTimer = NewPeriodicTimer(
+ alloc.refreshPermsTimer = NewPeriodicTimer(
timerIDRefreshPerms,
- a.onRefreshTimers,
+ alloc.onRefreshTimers,
permRefreshInterval,
)
- if a.refreshAllocTimer.Start() {
- a.log.Debug("Started refreshAllocTimer")
+ if alloc.refreshAllocTimer.Start() {
+ alloc.log.Debug("Started refreshAllocTimer")
}
- if a.refreshPermsTimer.Start() {
- a.log.Debug("Started refreshPermsTimer")
+ if alloc.refreshPermsTimer.Start() {
+ alloc.log.Debug("Started refreshPermsTimer")
}
- return a
+ return alloc
}
-// Connect sends a Connect request to the turn server and returns a chosen connection ID
+// Connect sends a Connect request to the turn server and returns a chosen connection ID.
func (a *TCPAllocation) Connect(peer net.Addr) (proto.ConnectionID, error) {
setters := []stun.Setter{
stun.TransactionID,
@@ -119,6 +119,7 @@ func (a *TCPAllocation) Connect(peer net.Addr) (proto.ConnectionID, error) {
}
a.log.Debugf("Connect request successful (cid=%v)", cid)
+
return cid, nil
}
@@ -218,8 +219,8 @@ func (a *TCPAllocation) DialTCPWithConn(conn net.Conn, _ string, rAddr *net.TCPA
return dataConn, nil
}
-// BindConnection associates the provided connection
-func (a *TCPAllocation) BindConnection(dataConn *TCPConn, cid proto.ConnectionID) error {
+// BindConnection associates the provided connection.
+func (a *TCPAllocation) BindConnection(dataConn *TCPConn, cid proto.ConnectionID) error { //nolint:cyclop
msg, err := stun.Build(
stun.TransactionID,
stun.NewType(stun.MethodConnectionBind, stun.ClassRequest),
@@ -272,9 +273,11 @@ func (a *TCPAllocation) BindConnection(dataConn *TCPConn, cid proto.ConnectionID
if err = code.GetFrom(res); err == nil {
return fmt.Errorf("%s (error %s)", res.Type, code) //nolint:goerr113
}
+
return fmt.Errorf("%s", res.Type) //nolint:goerr113
case stun.ClassSuccessResponse:
a.log.Debug("Successful connectionBind request")
+
return nil
default:
return fmt.Errorf("%w: %s", errUnexpectedSTUNRequestMessage, res.String())
@@ -347,6 +350,7 @@ func (a *TCPAllocation) SetDeadline(t time.Time) error {
d = time.Until(t)
}
a.acceptTimer.Reset(d)
+
return nil
}
@@ -358,10 +362,11 @@ func (a *TCPAllocation) Close() error {
a.refreshPermsTimer.Stop()
a.client.OnDeallocated(a.relayedAddr)
+
return a.refreshAllocation(0, true /* dontWait=true */)
}
-// Addr returns the relayed address of the allocation
+// Addr returns the relayed address of the allocation.
func (a *TCPAllocation) Addr() net.Addr {
return a.relayedAddr
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_conn.go
index 990b6d424..18330becd 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_conn.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/tcp_conn.go
@@ -23,7 +23,7 @@ const (
var _ transport.TCPConn = (*TCPConn)(nil) // Includes type check for net.Conn
// TCPConn wraps a transport.TCPConn and returns the allocations relayed
-// transport address in response to TCPConn.LocalAddress()
+// transport address in response to TCPConn.LocalAddress().
type TCPConn struct {
transport.TCPConn
remoteAddress *net.TCPAddr
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/transaction.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/transaction.go
index b1c9105e6..744df6689 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/transaction.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/transaction.go
@@ -15,7 +15,7 @@ const (
maxRtxInterval time.Duration = 1600 * time.Millisecond
)
-// TransactionResult is a bag of result values of a transaction
+// TransactionResult is a bag of result values of a transaction.
type TransactionResult struct {
Msg *stun.Message
From net.Addr
@@ -23,7 +23,7 @@ type TransactionResult struct {
Err error
}
-// TransactionConfig is a set of config params used by NewTransaction
+// TransactionConfig is a set of config params used by NewTransaction.
type TransactionConfig struct {
Key string
Raw []byte
@@ -32,7 +32,7 @@ type TransactionConfig struct {
IgnoreResult bool // True to throw away the result of this transaction (it will not be readable using WaitForResult)
}
-// Transaction represents a transaction
+// Transaction represents a transaction.
type Transaction struct {
Key string // Read-only
Raw []byte // Read-only
@@ -44,7 +44,7 @@ type Transaction struct {
mutex sync.RWMutex
}
-// NewTransaction creates a new instance of Transaction
+// NewTransaction creates a new instance of Transaction.
func NewTransaction(config *TransactionConfig) *Transaction {
var resultCh chan TransactionResult
if !config.IgnoreResult {
@@ -60,7 +60,7 @@ func NewTransaction(config *TransactionConfig) *Transaction {
}
}
-// StartRtxTimer starts the transaction timer
+// StartRtxTimer starts the transaction timer.
func (t *Transaction) StartRtxTimer(onTimeout func(trKey string, nRtx int)) {
t.mutex.Lock()
defer t.mutex.Unlock()
@@ -78,7 +78,7 @@ func (t *Transaction) StartRtxTimer(onTimeout func(trKey string, nRtx int)) {
})
}
-// StopRtxTimer stop the transaction timer
+// StopRtxTimer stop the transaction timer.
func (t *Transaction) StopRtxTimer() {
t.mutex.Lock()
defer t.mutex.Unlock()
@@ -88,7 +88,7 @@ func (t *Transaction) StopRtxTimer() {
}
}
-// WriteResult writes the result to the result channel
+// WriteResult writes the result to the result channel.
func (t *Transaction) WriteResult(res TransactionResult) bool {
if t.resultCh == nil {
return false
@@ -99,7 +99,7 @@ func (t *Transaction) WriteResult(res TransactionResult) bool {
return true
}
-// WaitForResult waits for the transaction result
+// WaitForResult waits for the transaction result.
func (t *Transaction) WaitForResult() TransactionResult {
if t.resultCh == nil {
return TransactionResult{
@@ -111,17 +111,18 @@ func (t *Transaction) WaitForResult() TransactionResult {
if !ok {
result.Err = errTransactionClosed
}
+
return result
}
-// Close closes the transaction
+// Close closes the transaction.
func (t *Transaction) Close() {
if t.resultCh != nil {
close(t.resultCh)
}
}
-// Retries returns the number of retransmission it has made
+// Retries returns the number of retransmission it has made.
func (t *Transaction) Retries() int {
t.mutex.RLock()
defer t.mutex.RUnlock()
@@ -129,38 +130,40 @@ func (t *Transaction) Retries() int {
return t.nRtx
}
-// TransactionMap is a thread-safe transaction map
+// TransactionMap is a thread-safe transaction map.
type TransactionMap struct {
trMap map[string]*Transaction
mutex sync.RWMutex
}
-// NewTransactionMap create a new instance of the transaction map
+// NewTransactionMap create a new instance of the transaction map.
func NewTransactionMap() *TransactionMap {
return &TransactionMap{
trMap: map[string]*Transaction{},
}
}
-// Insert inserts a transaction to the map
+// Insert inserts a transaction to the map.
func (m *TransactionMap) Insert(key string, tr *Transaction) bool {
m.mutex.Lock()
defer m.mutex.Unlock()
m.trMap[key] = tr
+
return true
}
-// Find looks up a transaction by its key
+// Find looks up a transaction by its key.
func (m *TransactionMap) Find(key string) (*Transaction, bool) {
m.mutex.RLock()
defer m.mutex.RUnlock()
tr, ok := m.trMap[key]
+
return tr, ok
}
-// Delete deletes a transaction by its key
+// Delete deletes a transaction by its key.
func (m *TransactionMap) Delete(key string) {
m.mutex.Lock()
defer m.mutex.Unlock()
@@ -168,7 +171,7 @@ func (m *TransactionMap) Delete(key string) {
delete(m.trMap, key)
}
-// CloseAndDeleteAll closes and deletes all transactions
+// CloseAndDeleteAll closes and deletes all transactions.
func (m *TransactionMap) CloseAndDeleteAll() {
m.mutex.Lock()
defer m.mutex.Unlock()
@@ -179,7 +182,7 @@ func (m *TransactionMap) CloseAndDeleteAll() {
}
}
-// Size returns the length of the transaction map
+// Size returns the length of the transaction map.
func (m *TransactionMap) Size() int {
m.mutex.RLock()
defer m.mutex.RUnlock()
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/trylock.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/trylock.go
index 6bfe6ff31..8380b0c8b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/trylock.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/trylock.go
@@ -18,6 +18,7 @@ func (c *TryLock) Lock() error {
if !atomic.CompareAndSwapInt32(&c.n, 0, 1) {
return errDoubleLock
}
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/udp_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/udp_conn.go
index 7bb187659..59d10ceaf 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/udp_conn.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/client/udp_conn.go
@@ -33,7 +33,7 @@ type inboundData struct {
}
// UDPConn is the implementation of the Conn and PacketConn interfaces for UDP network connections.
-// compatible with net.PacketConn and net.Conn
+// compatible with net.PacketConn and net.Conn.
type UDPConn struct {
bindingMgr *bindingManager // Thread-safe
readCh chan *inboundData // Thread-safe
@@ -41,9 +41,9 @@ type UDPConn struct {
allocation
}
-// NewUDPConn creates a new instance of UDPConn
+// NewUDPConn creates a new instance of UDPConn.
func NewUDPConn(config *AllocationConfig) *UDPConn {
- c := &UDPConn{
+ conn := &UDPConn{
bindingMgr: newBindingManager(),
readCh: make(chan *inboundData, maxReadQueueSize),
closeCh: make(chan struct{}),
@@ -63,28 +63,28 @@ func NewUDPConn(config *AllocationConfig) *UDPConn {
},
}
- c.log.Debugf("Initial lifetime: %d seconds", int(c.lifetime().Seconds()))
+ conn.log.Debugf("Initial lifetime: %d seconds", int(conn.lifetime().Seconds()))
- c.refreshAllocTimer = NewPeriodicTimer(
+ conn.refreshAllocTimer = NewPeriodicTimer(
timerIDRefreshAlloc,
- c.onRefreshTimers,
- c.lifetime()/2,
+ conn.onRefreshTimers,
+ conn.lifetime()/2,
)
- c.refreshPermsTimer = NewPeriodicTimer(
+ conn.refreshPermsTimer = NewPeriodicTimer(
timerIDRefreshPerms,
- c.onRefreshTimers,
+ conn.onRefreshTimers,
permRefreshInterval,
)
- if c.refreshAllocTimer.Start() {
- c.log.Debugf("Started refresh allocation timer")
+ if conn.refreshAllocTimer.Start() {
+ conn.log.Debugf("Started refresh allocation timer")
}
- if c.refreshPermsTimer.Start() {
- c.log.Debugf("Started refresh permission timer")
+ if conn.refreshPermsTimer.Start() {
+ conn.log.Debugf("Started refresh permission timer")
}
- return c
+ return conn
}
// ReadFrom reads a packet from the connection,
@@ -105,6 +105,7 @@ func (c *UDPConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
if n < len(ibData.data) {
return 0, nil, io.ErrShortBuffer
}
+
return n, ibData.from, nil
case <-c.readTimer.C:
@@ -134,19 +135,21 @@ func (a *allocation) createPermission(perm *permission, addr net.Addr) error {
// Punch a hole! (this would block a bit..)
if err := a.CreatePermissions(addr); err != nil {
a.permMap.delete(addr)
+
return err
}
perm.setState(permStatePermitted)
}
+
return nil
}
-// WriteTo writes a packet with payload p to addr.
+// WriteTo writes a packet with payload to addr.
// WriteTo can be made to time out and return
// an Error with Timeout() == true after a fixed time limit;
// see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
-func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (int, error) { //nolint: gocognit
+func (c *UDPConn) WriteTo(payload []byte, addr net.Addr) (int, error) { //nolint:gocognit,cyclop
var err error
_, ok := addr.(*net.UDPAddr)
if !ok {
@@ -177,31 +180,32 @@ func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (int, error) { //nolint: goco
}
// Bind channel
- b, ok := c.bindingMgr.findByAddr(addr)
+ bound, ok := c.bindingMgr.findByAddr(addr)
if !ok {
- b = c.bindingMgr.create(addr)
+ bound = c.bindingMgr.create(addr)
}
- bindSt := b.state()
+ bindSt := bound.state()
+ //nolint:nestif
if bindSt == bindingStateIdle || bindSt == bindingStateRequest || bindSt == bindingStateFailed {
func() {
// Block only callers with the same binding until
// the binding transaction has been complete
- b.muBind.Lock()
- defer b.muBind.Unlock()
+ bound.muBind.Lock()
+ defer bound.muBind.Unlock()
// Binding state may have been changed while waiting. check again.
- if b.state() == bindingStateIdle {
- b.setState(bindingStateRequest)
+ if bound.state() == bindingStateIdle {
+ bound.setState(bindingStateRequest)
go func() {
- err2 := c.bind(b)
+ err2 := c.bind(bound)
if err2 != nil {
c.log.Warnf("Failed to bind bind(): %s", err2)
- b.setState(bindingStateFailed)
+ bound.setState(bindingStateFailed)
// Keep going...
} else {
- b.setState(bindingStateReady)
+ bound.setState(bindingStateReady)
}
}()
}
@@ -213,7 +217,7 @@ func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (int, error) { //nolint: goco
msg, err = stun.Build(
stun.TransactionID,
stun.NewType(stun.MethodSend, stun.ClassIndication),
- proto.Data(p),
+ proto.Data(payload),
peerAddr,
stun.Fingerprint,
)
@@ -230,31 +234,31 @@ func (c *UDPConn) WriteTo(p []byte, addr net.Addr) (int, error) { //nolint: goco
// Check if the binding needs a refresh
func() {
- b.muBind.Lock()
- defer b.muBind.Unlock()
+ bound.muBind.Lock()
+ defer bound.muBind.Unlock()
- if b.state() == bindingStateReady && time.Since(b.refreshedAt()) > 5*time.Minute {
- b.setState(bindingStateRefresh)
+ if bound.state() == bindingStateReady && time.Since(bound.refreshedAt()) > 5*time.Minute {
+ bound.setState(bindingStateRefresh)
go func() {
- err = c.bind(b)
- if err != nil {
- c.log.Warnf("Failed to bind() for refresh: %s", err)
- b.setState(bindingStateFailed)
+ if bindErr := c.bind(bound); bindErr != nil {
+ c.log.Warnf("Failed to bind() for refresh: %s", bindErr)
+ bound.setState(bindingStateFailed)
// Keep going...
} else {
- b.setRefreshedAt(time.Now())
- b.setState(bindingStateReady)
+ bound.setRefreshedAt(time.Now())
+ bound.setState(bindingStateReady)
}
}()
}
}()
// Send via ChannelData
- _, err = c.sendChannelData(p, b.number)
+ _, err = c.sendChannelData(payload, bound.number)
if err != nil {
return 0, err
}
- return len(p), nil
+
+ return len(payload), nil
}
// Close closes the connection.
@@ -271,6 +275,7 @@ func (c *UDPConn) Close() error {
}
c.client.OnDeallocated(c.relayedAddr)
+
return c.refreshAllocation(0, true /* dontWait=true */)
}
@@ -309,6 +314,7 @@ func (c *UDPConn) SetReadDeadline(t time.Time) error {
d = time.Until(t)
}
c.readTimer.Reset(d)
+
return nil
}
@@ -372,17 +378,20 @@ func (a *allocation) CreatePermissions(addrs ...net.Addr) error {
if err = code.GetFrom(res); err == nil {
if code.Code == stun.CodeStaleNonce {
a.setNonceFromMsg(res)
+
return errTryAgain
}
+
return fmt.Errorf("%s (error %s)", res.Type, code) //nolint:goerr113
}
+
return fmt.Errorf("%s", res.Type) //nolint:goerr113
}
return nil
}
-// HandleInbound passes inbound data in UDPConn
+// HandleInbound passes inbound data in UDPConn.
func (c *UDPConn) HandleInbound(data []byte, from net.Addr) {
// Copy data
copied := make([]byte, len(data))
@@ -396,21 +405,22 @@ func (c *UDPConn) HandleInbound(data []byte, from net.Addr) {
}
// FindAddrByChannelNumber returns a peer address associated with the
-// channel number on this UDPConn
+// channel number on this UDPConn.
func (c *UDPConn) FindAddrByChannelNumber(chNum uint16) (net.Addr, bool) {
b, ok := c.bindingMgr.findByNumber(chNum)
if !ok {
return nil, false
}
+
return b.addr, true
}
-func (c *UDPConn) bind(b *binding) error {
+func (c *UDPConn) bind(bound *binding) error {
setters := []stun.Setter{
stun.TransactionID,
stun.NewType(stun.MethodChannelBind, stun.ClassRequest),
- addr2PeerAddress(b.addr),
- proto.ChannelNumber(b.number),
+ addr2PeerAddress(bound.addr),
+ proto.ChannelNumber(bound.number),
c.username,
c.realm,
c.nonce(),
@@ -425,7 +435,8 @@ func (c *UDPConn) bind(b *binding) error {
trRes, err := c.client.PerformTransaction(msg, c.serverAddr, false)
if err != nil {
- c.bindingMgr.deleteByAddr(b.addr)
+ c.bindingMgr.deleteByAddr(bound.addr)
+
return err
}
@@ -435,7 +446,7 @@ func (c *UDPConn) bind(b *binding) error {
return fmt.Errorf("unexpected response type %s", res.Type) //nolint:goerr113
}
- c.log.Debugf("Channel binding successful: %s %d", b.addr, b.number)
+ c.log.Debugf("Channel binding successful: %s %d", bound.addr, bound.number)
// Success.
return nil
@@ -451,5 +462,6 @@ func (c *UDPConn) sendChannelData(data []byte, chNum uint16) (int, error) {
if err != nil {
return 0, err
}
+
return len(data), nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/ipnet/util.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/ipnet/util.go
index c3a5b32f3..9753ef35c 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/ipnet/util.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/ipnet/util.go
@@ -11,7 +11,7 @@ import (
var errFailedToCastAddr = errors.New("failed to cast net.Addr to *net.UDPAddr or *net.TCPAddr")
-// AddrIPPort extracts the IP and Port from a net.Addr
+// AddrIPPort extracts the IP and Port from a net.Addr.
func AddrIPPort(a net.Addr) (net.IP, int, error) {
aUDP, ok := a.(*net.UDPAddr)
if ok {
@@ -27,7 +27,7 @@ func AddrIPPort(a net.Addr) (net.IP, int, error) {
}
// AddrEqual asserts that two net.Addrs are equal
-// Currently only supports UDP but will be extended in the future to support others
+// Currently only supports UDP but will be extended in the future to support others.
func AddrEqual(a, b net.Addr) bool {
aUDP, ok := a.(*net.UDPAddr)
if !ok {
@@ -51,5 +51,6 @@ func FingerprintAddr(addr net.Addr) string {
case *net.TCPAddr: // Do we really need this case?
return a.IP.String()
}
+
return "" // Should never happen
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/addr.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/addr.go
index 7d4db8bf7..38b3027fc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/addr.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/addr.go
@@ -28,6 +28,7 @@ func (a Addr) Equal(b Addr) bool {
if a.Port != b.Port {
return false
}
+
return a.IP.Equal(b.IP)
}
@@ -64,5 +65,6 @@ func (t FiveTuple) Equal(b FiveTuple) bool {
if !t.Server.Equal(b.Server) {
return false
}
+
return true
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chandata.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chandata.go
index df9371193..4c9bb2620 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chandata.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chandata.go
@@ -12,7 +12,7 @@ import (
// ChannelData represents The ChannelData Message.
//
-// See RFC 5766 Section 11.4
+// See RFC 5766 Section 11.4.
type ChannelData struct {
Data []byte // Can be sub slice of Raw
Length int // Ignored while encoding, len(Data) is used
@@ -20,21 +20,22 @@ type ChannelData struct {
Raw []byte
}
-// Equal returns true if b == c.
-func (c *ChannelData) Equal(b *ChannelData) bool {
- if c == nil && b == nil {
+// Equal returns true if compareTo == c.
+func (c *ChannelData) Equal(compareTo *ChannelData) bool {
+ if c == nil && compareTo == nil {
return true
}
- if c == nil || b == nil {
+ if c == nil || compareTo == nil {
return false
}
- if c.Number != b.Number {
+ if c.Number != compareTo.Number {
return false
}
- if len(c.Data) != len(b.Data) {
+ if len(c.Data) != len(compareTo.Data) {
return false
}
- return bytes.Equal(c.Data, b.Data)
+
+ return bytes.Equal(c.Data, compareTo.Data)
}
// Grow ensures that internal buffer will fit v more bytes and
@@ -76,6 +77,7 @@ func nearestPaddedValueLength(l int) int {
if n < l {
n += padding
}
+
return n
}
@@ -90,7 +92,7 @@ func (c *ChannelData) WriteHeader() {
_ = c.Raw[:channelDataHeaderSize]
binary.BigEndian.PutUint16(c.Raw[:channelDataNumberSize], uint16(c.Number))
binary.BigEndian.PutUint16(c.Raw[channelDataNumberSize:channelDataHeaderSize],
- uint16(len(c.Data)),
+ uint16(len(c.Data)), // nolint:gosec // G115
)
}
@@ -118,6 +120,7 @@ func (c *ChannelData) Decode() error {
if int(l) > len(buf[channelDataHeaderSize:]) {
return ErrBadChannelDataLength
}
+
return nil
}
@@ -139,5 +142,6 @@ func IsChannelData(buf []byte) bool {
// Quick check for channel number.
num := binary.BigEndian.Uint16(buf[0:channelNumberSize])
+
return isChannelNumberValid(num)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chann.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chann.go
index 3aeb59f38..da017bf65 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chann.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/chann.go
@@ -15,7 +15,7 @@ import (
//
// The CHANNEL-NUMBER attribute contains the number of the channel.
//
-// RFC 5766 Section 14.1
+// RFC 5766 Section 14.1.
type ChannelNumber uint16 // Encoded as uint16
func (n ChannelNumber) String() string { return strconv.Itoa(int(n)) }
@@ -29,6 +29,7 @@ func (n ChannelNumber) AddTo(m *stun.Message) error {
binary.BigEndian.PutUint16(v[:2], uint16(n))
// v[2:4] are zeroes (RFFU = 0)
m.Add(stun.AttrChannelNumber, v)
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/connection_id.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/connection_id.go
index 568deff15..d95d9b045 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/connection_id.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/connection_id.go
@@ -14,7 +14,7 @@ import (
// The CONNECTION-ID attribute uniquely identifies a peer data
// connection. It is a 32-bit unsigned integral value.
//
-// RFC 6062 Section 6.2.1
+// RFC 6062 Section 6.2.1.
type ConnectionID uint32
const connectionIDSize = 4 // uint32: 4 bytes, 32 bits
@@ -24,6 +24,7 @@ func (c ConnectionID) AddTo(m *stun.Message) error {
v := make([]byte, lifetimeSize)
binary.BigEndian.PutUint32(v, uint32(c))
m.Add(stun.AttrConnectionID, v)
+
return nil
}
@@ -38,5 +39,6 @@ func (c *ConnectionID) GetFrom(m *stun.Message) error {
}
_ = v[connectionIDSize-1] // Asserting length
*(*uint32)(c) = binary.BigEndian.Uint32(v)
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/data.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/data.go
index dcba23b44..ea2f0c868 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/data.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/data.go
@@ -13,12 +13,13 @@ import "github.com/pion/stun/v3"
// the UDP header if the data was been sent directly between the client
// and the peer).
//
-// RFC 5766 Section 14.4
+// RFC 5766 Section 14.4.
type Data []byte
// AddTo adds DATA to message.
func (d Data) AddTo(m *stun.Message) error {
m.Add(stun.AttrData, d)
+
return nil
}
@@ -29,5 +30,6 @@ func (d *Data) GetFrom(m *stun.Message) error {
return err
}
*d = v
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/dontfrag.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/dontfrag.go
index e4be0af67..d46ae8f14 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/dontfrag.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/dontfrag.go
@@ -8,7 +8,7 @@ import (
)
// DontFragmentAttr is a deprecated alias for DontFragment
-// Deprecated: Please use DontFragment
+// Deprecated: Please use DontFragment.
type DontFragmentAttr = DontFragment
// DontFragment represents DONT-FRAGMENT attribute.
@@ -18,7 +18,7 @@ type DontFragmentAttr = DontFragment
// application data onward to the peer. This attribute has no value
// part and thus the attribute length field is 0.
//
-// RFC 5766 Section 14.8
+// RFC 5766 Section 14.8.
type DontFragment struct{}
const dontFragmentSize = 0
@@ -26,6 +26,7 @@ const dontFragmentSize = 0
// AddTo adds DONT-FRAGMENT attribute to message.
func (DontFragment) AddTo(m *stun.Message) error {
m.Add(stun.AttrDontFragment, nil)
+
return nil
}
@@ -35,11 +36,13 @@ func (d *DontFragment) GetFrom(m *stun.Message) error {
if err != nil {
return err
}
+
return stun.CheckSize(stun.AttrDontFragment, len(v), dontFragmentSize)
}
// IsSet returns true if DONT-FRAGMENT attribute is set.
func (DontFragment) IsSet(m *stun.Message) bool {
_, err := m.Get(stun.AttrDontFragment)
+
return err == nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/evenport.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/evenport.go
index 31468c757..6989ab894 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/evenport.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/evenport.go
@@ -11,7 +11,7 @@ import "github.com/pion/stun/v3"
// relayed transport address be even, and (optionally) that the server
// reserve the next-higher port number.
//
-// RFC 5766 Section 14.6
+// RFC 5766 Section 14.6.
type EvenPort struct {
// ReservePort means that the server is requested to reserve
// the next-higher port number (on the same IP address)
@@ -23,6 +23,7 @@ func (p EvenPort) String() string {
if p.ReservePort {
return "reserve: true"
}
+
return "reserve: false"
}
@@ -39,6 +40,7 @@ func (p EvenPort) AddTo(m *stun.Message) error {
v[0] = firstBitSet
}
m.Add(stun.AttrEvenPort, v)
+
return nil
}
@@ -54,5 +56,6 @@ func (p *EvenPort) GetFrom(m *stun.Message) error {
if v[0]&firstBitSet > 0 {
p.ReservePort = true
}
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/lifetime.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/lifetime.go
index 6f55c7a97..37b86f81a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/lifetime.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/lifetime.go
@@ -12,7 +12,7 @@ import (
// DefaultLifetime in RFC 5766 is 10 minutes.
//
-// RFC 5766 Section 2.2
+// RFC 5766 Section 2.2.
const DefaultLifetime = time.Minute * 10
// Lifetime represents LIFETIME attribute.
@@ -23,12 +23,12 @@ const DefaultLifetime = time.Minute * 10
// unsigned integral value representing the number of seconds remaining
// until expiration.
//
-// RFC 5766 Section 14.2
+// RFC 5766 Section 14.2.
type Lifetime struct {
time.Duration
}
-// Seconds in uint32
+// Seconds in uint32.
const lifetimeSize = 4 // 4 bytes, 32 bits
// AddTo adds LIFETIME to message.
@@ -36,6 +36,7 @@ func (l Lifetime) AddTo(m *stun.Message) error {
v := make([]byte, lifetimeSize)
binary.BigEndian.PutUint32(v, uint32(l.Seconds()))
m.Add(stun.AttrLifetime, v)
+
return nil
}
@@ -51,5 +52,6 @@ func (l *Lifetime) GetFrom(m *stun.Message) error {
_ = v[lifetimeSize-1] // Asserting length
seconds := binary.BigEndian.Uint32(v)
l.Duration = time.Second * time.Duration(seconds)
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/peeraddr.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/peeraddr.go
index f4d9de7b6..a919bd15a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/peeraddr.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/peeraddr.go
@@ -15,7 +15,7 @@ import (
// seen from the TURN server. (For example, the peer's server-reflexive
// transport address if the peer is behind a NAT.)
//
-// RFC 5766 Section 14.3
+// RFC 5766 Section 14.3.
type PeerAddress struct {
IP net.IP
Port int
@@ -41,5 +41,5 @@ func (a *PeerAddress) GetFrom(m *stun.Message) error {
// seen from the TURN server. (For example, the peer's server-reflexive
// transport address if the peer is behind a NAT.)
//
-// RFC 5766 Section 14.3
+// RFC 5766 Section 14.3.
type XORPeerAddress = PeerAddress
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/relayedaddr.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/relayedaddr.go
index c5fb2686c..1d22ade9e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/relayedaddr.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/relayedaddr.go
@@ -14,7 +14,7 @@ import (
// It specifies the address and port that the server allocated to the
// client. It is encoded in the same way as XOR-MAPPED-ADDRESS.
//
-// RFC 5766 Section 14.5
+// RFC 5766 Section 14.5.
type RelayedAddress struct {
IP net.IP
Port int
@@ -39,5 +39,5 @@ func (a *RelayedAddress) GetFrom(m *stun.Message) error {
// It specifies the address and port that the server allocated to the
// client. It is encoded in the same way as XOR-MAPPED-ADDRESS.
//
-// RFC 5766 Section 14.5
+// RFC 5766 Section 14.5.
type XORRelayedAddress = RelayedAddress
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqfamily.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqfamily.go
index 01016a987..d00c302fc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqfamily.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqfamily.go
@@ -32,6 +32,7 @@ func (f *RequestedAddressFamily) GetFrom(m *stun.Message) error {
default:
return errInvalidRequestedFamilyValue
}
+
return nil
}
@@ -54,6 +55,7 @@ func (f RequestedAddressFamily) AddTo(m *stun.Message) error {
// The RFFU field MUST be set to zero on transmission and MUST be
// ignored on reception. It is reserved for future uses.
m.Add(stun.AttrRequestedAddressFamily, v)
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqtrans.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqtrans.go
index 111dcd69b..b907e3846 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqtrans.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/reqtrans.go
@@ -36,7 +36,7 @@ func (p Protocol) String() string {
// protocol for the allocated transport address. RFC 5766 only allows the use of
// code point 17 (User Datagram Protocol).
//
-// RFC 5766 Section 14.7
+// RFC 5766 Section 14.7.
type RequestedTransport struct {
Protocol Protocol
}
@@ -55,6 +55,7 @@ func (t RequestedTransport) AddTo(m *stun.Message) error {
// The RFFU field MUST be set to zero on transmission and MUST be
// ignored on reception. It is reserved for future uses.
m.Add(stun.AttrRequestedTransport, v)
+
return nil
}
@@ -68,5 +69,6 @@ func (t *RequestedTransport) GetFrom(m *stun.Message) error {
return err
}
t.Protocol = Protocol(v[0])
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/rsrvtoken.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/rsrvtoken.go
index 9c816485d..aed38861a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/rsrvtoken.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/proto/rsrvtoken.go
@@ -14,7 +14,7 @@ import "github.com/pion/stun/v3"
// attribute in a subsequent Allocate request to request the server use
// that relayed transport address for the allocation.
//
-// RFC 5766 Section 14.9
+// RFC 5766 Section 14.9.
type ReservationToken []byte
const reservationTokenSize = 8 // 8 bytes
@@ -25,6 +25,7 @@ func (t ReservationToken) AddTo(m *stun.Message) error {
return err
}
m.Add(stun.AttrReservationToken, t)
+
return nil
}
@@ -38,5 +39,6 @@ func (t *ReservationToken) GetFrom(m *stun.Message) error {
return err
}
*t = v
+
return nil
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/nonce.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/nonce.go
index b3f3131e8..22e466f98 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/nonce.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/nonce.go
@@ -19,7 +19,7 @@ const (
nonceKeyLength = 64
)
-// NewNonceHash creates a NonceHash
+// NewNonceHash creates a NonceHash.
func NewNonceHash() (*NonceHash, error) {
key := make([]byte, nonceKeyLength)
if _, err := rand.Read(key); err != nil {
@@ -29,15 +29,15 @@ func NewNonceHash() (*NonceHash, error) {
return &NonceHash{key}, nil
}
-// NonceHash is used to create and verify nonces
+// NonceHash is used to create and verify nonces.
type NonceHash struct {
key []byte
}
-// Generate a nonce
+// Generate a nonce.
func (n *NonceHash) Generate() (string, error) {
nonce := make([]byte, 8, nonceLength)
- binary.BigEndian.PutUint64(nonce, uint64(time.Now().UnixMilli()))
+ binary.BigEndian.PutUint64(nonce, uint64(time.Now().UnixMilli())) // nolint:gosec // G115
hash := hmac.New(sha256.New, n.key)
if _, err := hash.Write(nonce[:8]); err != nil {
@@ -48,14 +48,14 @@ func (n *NonceHash) Generate() (string, error) {
return hex.EncodeToString(nonce), nil
}
-// Validate checks that nonce is signed and is not expired
+// Validate checks that nonce is signed and is not expired.
func (n *NonceHash) Validate(nonce string) error {
b, err := hex.DecodeString(nonce)
if err != nil || len(b) != nonceLength {
return fmt.Errorf("%w: %v", errInvalidNonce, err) //nolint:errorlint
}
- if ts := time.UnixMilli(int64(binary.BigEndian.Uint64(b))); time.Since(ts) > nonceLifetime {
+ if ts := time.UnixMilli(int64(binary.BigEndian.Uint64(b))); time.Since(ts) > nonceLifetime { // nolint:gosec // G115
return errInvalidNonce
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/server.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/server.go
index 253492e92..4f5c31486 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/server.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/server.go
@@ -15,7 +15,7 @@ import (
"github.com/pion/turn/v4/internal/proto"
)
-// Request contains all the state needed to process a single incoming datagram
+// Request contains all the state needed to process a single incoming datagram.
type Request struct {
// Current Request State
Conn net.PacketConn
@@ -33,7 +33,7 @@ type Request struct {
ChannelBindTimeout time.Duration
}
-// HandleRequest processes the give Request
+// HandleRequest processes the give Request.
func HandleRequest(r Request) error {
r.Log.Debugf("Received %d bytes of udp from %s on %s", len(r.Buff), r.SrcAddr, r.Conn.LocalAddr())
@@ -44,42 +44,62 @@ func HandleRequest(r Request) error {
return handleTURNPacket(r)
}
-func handleDataPacket(r Request) error {
- r.Log.Debugf("Received DataPacket from %s", r.SrcAddr.String())
- c := proto.ChannelData{Raw: r.Buff}
+func handleDataPacket(req Request) error {
+ req.Log.Debugf("Received DataPacket from %s", req.SrcAddr.String())
+ c := proto.ChannelData{Raw: req.Buff}
if err := c.Decode(); err != nil {
return fmt.Errorf("%w: %v", errFailedToCreateChannelData, err) //nolint:errorlint
}
- err := handleChannelData(r, &c)
+ err := handleChannelData(req, &c)
if err != nil {
- err = fmt.Errorf("%w from %v: %v", errUnableToHandleChannelData, r.SrcAddr, err) //nolint:errorlint
+ err = fmt.Errorf("%w from %v: %v", errUnableToHandleChannelData, req.SrcAddr, err) //nolint:errorlint
}
return err
}
-func handleTURNPacket(r Request) error {
- r.Log.Debug("Handling TURN packet")
- m := &stun.Message{Raw: append([]byte{}, r.Buff...)}
- if err := m.Decode(); err != nil {
- return fmt.Errorf("%w: %v", errFailedToCreateSTUNPacket, err) //nolint:errorlint
+func handleTURNPacket(req Request) error {
+ req.Log.Debug("Handling TURN packet")
+ stunMsg := &stun.Message{Raw: append([]byte{}, req.Buff...)}
+ if err := stunMsg.Decode(); err != nil {
+ // nolint:errorlint
+ return fmt.Errorf("%w: %v", errFailedToCreateSTUNPacket, err)
}
- h, err := getMessageHandler(m.Type.Class, m.Type.Method)
+ handler, err := getMessageHandler(stunMsg.Type.Class, stunMsg.Type.Method)
if err != nil {
- return fmt.Errorf("%w %v-%v from %v: %v", errUnhandledSTUNPacket, m.Type.Method, m.Type.Class, r.SrcAddr, err) //nolint:errorlint
+ // nolint:errorlint
+ return fmt.Errorf(
+ "%w %v-%v from %v: %v",
+ errUnhandledSTUNPacket,
+ stunMsg.Type.Method,
+ stunMsg.Type.Class,
+ req.SrcAddr,
+ err,
+ )
}
- err = h(r, m)
+ err = handler(req, stunMsg)
if err != nil {
- return fmt.Errorf("%w %v-%v from %v: %v", errFailedToHandle, m.Type.Method, m.Type.Class, r.SrcAddr, err) //nolint:errorlint
+ // nolint:errorlint
+ return fmt.Errorf(
+ "%w %v-%v from %v: %v",
+ errFailedToHandle,
+ stunMsg.Type.Method,
+ stunMsg.Type.Class,
+ req.SrcAddr,
+ err,
+ )
}
return nil
}
-func getMessageHandler(class stun.MessageClass, method stun.Method) (func(r Request, m *stun.Message) error, error) {
+func getMessageHandler(class stun.MessageClass, method stun.Method) ( // nolint:cyclop
+ func(req Request, stunMsg *stun.Message) error,
+ error,
+) {
switch class {
case stun.ClassIndication:
switch method {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/stun.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/stun.go
index 393bb99d8..1880bf177 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/stun.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/stun.go
@@ -8,18 +8,18 @@ import (
"github.com/pion/turn/v4/internal/ipnet"
)
-func handleBindingRequest(r Request, m *stun.Message) error {
- r.Log.Debugf("Received BindingRequest from %s", r.SrcAddr)
+func handleBindingRequest(req Request, stunMsg *stun.Message) error {
+ req.Log.Debugf("Received BindingRequest from %s", req.SrcAddr)
- ip, port, err := ipnet.AddrIPPort(r.SrcAddr)
+ ip, port, err := ipnet.AddrIPPort(req.SrcAddr)
if err != nil {
return err
}
- attrs := buildMsg(m.TransactionID, stun.BindingSuccess, &stun.XORMappedAddress{
+ attrs := buildMsg(stunMsg.TransactionID, stun.BindingSuccess, &stun.XORMappedAddress{
IP: ip,
Port: port,
}, stun.Fingerprint)
- return buildAndSend(r.Conn, r.SrcAddr, attrs...)
+ return buildAndSend(req.Conn, req.SrcAddr, attrs...)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/turn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/turn.go
index 46e45ecbe..d20c5dc56 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/turn.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/turn.go
@@ -17,42 +17,61 @@ import (
const runesAlpha = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
// See: https://tools.ietf.org/html/rfc5766#section-6.2
-func handleAllocateRequest(r Request, m *stun.Message) error {
- r.Log.Debugf("Received AllocateRequest from %s", r.SrcAddr)
+// .
+func handleAllocateRequest(req Request, stunMsg *stun.Message) error { //nolint:cyclop
+ req.Log.Debugf("Received AllocateRequest from %s", req.SrcAddr)
// 1. The server MUST require that the request be authenticated. This
// authentication MUST be done using the long-term credential
// mechanism of [https://tools.ietf.org/html/rfc5389#section-10.2.2]
// unless the client and server agree to use another mechanism through
// some procedure outside the scope of this document.
- messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodAllocate)
+ messageIntegrity, hasAuth, err := authenticateRequest(req, stunMsg, stun.MethodAllocate)
if !hasAuth {
return err
}
fiveTuple := &allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
}
requestedPort := 0
reservationToken := ""
- badRequestMsg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest})
- insufficientCapacityMsg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeInsufficientCapacity})
+ badRequestMsg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest},
+ )
+ insufficientCapacityMsg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeInsufficientCapacity},
+ )
// 2. The server checks if the 5-tuple is currently in use by an
// existing allocation. If yes, the server rejects the request with
// a 437 (Allocation Mismatch) error.
- if alloc := r.AllocationManager.GetAllocation(fiveTuple); alloc != nil {
+ if alloc := req.AllocationManager.GetAllocation(fiveTuple); alloc != nil {
id, attrs := alloc.GetResponseCache()
- if id != m.TransactionID {
- msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeAllocMismatch})
- return buildAndSendErr(r.Conn, r.SrcAddr, errRelayAlreadyAllocatedForFiveTuple, msg...)
+ if id != stunMsg.TransactionID {
+ msg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeAllocMismatch},
+ )
+
+ return buildAndSendErr(req.Conn, req.SrcAddr, errRelayAlreadyAllocatedForFiveTuple, msg...)
}
// A retry allocation
- msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(attrs, messageIntegrity)...)
- return buildAndSend(r.Conn, r.SrcAddr, msg...)
+ msg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse),
+ append(attrs, messageIntegrity)...,
+ )
+
+ return buildAndSend(req.Conn, req.SrcAddr, msg...)
}
// 3. The server checks if the request contains a REQUESTED-TRANSPORT
@@ -62,11 +81,16 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// specifies a protocol other that UDP/TCP, the server rejects the
// request with a 442 (Unsupported Transport Protocol) error.
var requestedTransport proto.RequestedTransport
- if err = requestedTransport.GetFrom(m); err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err = requestedTransport.GetFrom(stunMsg); err != nil {
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
} else if requestedTransport.Protocol != proto.ProtoUDP && requestedTransport.Protocol != proto.ProtoTCP {
- msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeUnsupportedTransProto})
- return buildAndSendErr(r.Conn, r.SrcAddr, errUnsupportedTransportProtocol, msg...)
+ msg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeUnsupportedTransProto},
+ )
+
+ return buildAndSendErr(req.Conn, req.SrcAddr, errUnsupportedTransportProtocol, msg...)
}
// 4. The request may contain a DONT-FRAGMENT attribute. If it does,
@@ -74,9 +98,15 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// bit set to 1 (see Section 12), then the server treats the DONT-
// FRAGMENT attribute in the Allocate request as an unknown
// comprehension-required attribute.
- if m.Contains(stun.AttrDontFragment) {
- msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeUnknownAttribute}, &stun.UnknownAttributes{stun.AttrDontFragment})
- return buildAndSendErr(r.Conn, r.SrcAddr, errNoDontFragmentSupport, msg...)
+ if stunMsg.Contains(stun.AttrDontFragment) {
+ msg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeUnknownAttribute},
+ &stun.UnknownAttributes{stun.AttrDontFragment},
+ )
+
+ return buildAndSendErr(req.Conn, req.SrcAddr, errNoDontFragmentSupport, msg...)
}
// 5. The server checks if the request contains a RESERVATION-TOKEN
@@ -88,10 +118,10 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// the token is not valid for some reason, the server rejects the
// request with a 508 (Insufficient Capacity) error.
var reservationTokenAttr proto.ReservationToken
- if err = reservationTokenAttr.GetFrom(m); err == nil {
+ if err = reservationTokenAttr.GetFrom(stunMsg); err == nil {
var evenPort proto.EvenPort
- if err = evenPort.GetFrom(m); err == nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, errRequestWithReservationTokenAndEvenPort, badRequestMsg...)
+ if err = evenPort.GetFrom(stunMsg); err == nil {
+ return buildAndSendErr(req.Conn, req.SrcAddr, errRequestWithReservationTokenAndEvenPort, badRequestMsg...)
}
}
@@ -102,11 +132,11 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// server rejects the request with a 508 (Insufficient Capacity)
// error.
var evenPort proto.EvenPort
- if err = evenPort.GetFrom(m); err == nil {
+ if err = evenPort.GetFrom(stunMsg); err == nil {
var randomPort int
- randomPort, err = r.AllocationManager.GetRandomEvenPort()
+ randomPort, err = req.AllocationManager.GetRandomEvenPort()
if err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, insufficientCapacityMsg...)
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, insufficientCapacityMsg...)
}
requestedPort = randomPort
reservationToken, err = randutil.GenerateCryptoRandomString(8, runesAlpha)
@@ -126,14 +156,14 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// with a 300 (Try Alternate) error if it wishes to redirect the
// client to a different server. The use of this error code and
// attribute follow the specification in [RFC5389].
- lifetimeDuration := allocationLifeTime(m)
- a, err := r.AllocationManager.CreateAllocation(
+ lifetimeDuration := allocationLifeTime(stunMsg)
+ alloc, err := req.AllocationManager.CreateAllocation(
fiveTuple,
- r.Conn,
+ req.Conn,
requestedPort,
lifetimeDuration)
if err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, insufficientCapacityMsg...)
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, insufficientCapacityMsg...)
}
// Once the allocation is created, the server replies with a success
@@ -148,14 +178,14 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
// * An XOR-MAPPED-ADDRESS attribute containing the client's IP address
// and port (from the 5-tuple).
- srcIP, srcPort, err := ipnet.AddrIPPort(r.SrcAddr)
+ srcIP, srcPort, err := ipnet.AddrIPPort(req.SrcAddr)
if err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
- relayIP, relayPort, err := ipnet.AddrIPPort(a.RelayAddr)
+ relayIP, relayPort, err := ipnet.AddrIPPort(alloc.RelayAddr)
if err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
responseAttrs := []stun.Setter{
@@ -173,90 +203,105 @@ func handleAllocateRequest(r Request, m *stun.Message) error {
}
if reservationToken != "" {
- r.AllocationManager.CreateReservation(reservationToken, relayPort)
+ req.AllocationManager.CreateReservation(reservationToken, relayPort)
responseAttrs = append(responseAttrs, proto.ReservationToken([]byte(reservationToken)))
}
- msg := buildMsg(m.TransactionID, stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse), append(responseAttrs, messageIntegrity)...)
- a.SetResponseCache(m.TransactionID, responseAttrs)
- return buildAndSend(r.Conn, r.SrcAddr, msg...)
+ msg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodAllocate, stun.ClassSuccessResponse),
+ append(responseAttrs, messageIntegrity)...,
+ )
+ alloc.SetResponseCache(stunMsg.TransactionID, responseAttrs)
+
+ return buildAndSend(req.Conn, req.SrcAddr, msg...)
}
-func handleRefreshRequest(r Request, m *stun.Message) error {
- r.Log.Debugf("Received RefreshRequest from %s", r.SrcAddr)
+func handleRefreshRequest(req Request, stunMsg *stun.Message) error {
+ req.Log.Debugf("Received RefreshRequest from %s", req.SrcAddr)
- messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodRefresh)
+ messageIntegrity, hasAuth, err := authenticateRequest(req, stunMsg, stun.MethodRefresh)
if !hasAuth {
return err
}
- lifetimeDuration := allocationLifeTime(m)
+ lifetimeDuration := allocationLifeTime(stunMsg)
fiveTuple := &allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
}
if lifetimeDuration != 0 {
- a := r.AllocationManager.GetAllocation(fiveTuple)
+ a := req.AllocationManager.GetAllocation(fiveTuple)
if a == nil {
- return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
+ return fmt.Errorf("%w %v:%v", errNoAllocationFound, req.SrcAddr, req.Conn.LocalAddr())
}
a.Refresh(lifetimeDuration)
} else {
- r.AllocationManager.DeleteAllocation(fiveTuple)
+ req.AllocationManager.DeleteAllocation(fiveTuple)
}
- return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodRefresh, stun.ClassSuccessResponse), []stun.Setter{
- &proto.Lifetime{
- Duration: lifetimeDuration,
- },
- messageIntegrity,
- }...)...)
+ return buildAndSend(
+ req.Conn,
+ req.SrcAddr,
+ buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodRefresh, stun.ClassSuccessResponse),
+ []stun.Setter{
+ &proto.Lifetime{
+ Duration: lifetimeDuration,
+ },
+ messageIntegrity,
+ }...,
+ )...,
+ )
}
-func handleCreatePermissionRequest(r Request, m *stun.Message) error {
- r.Log.Debugf("Received CreatePermission from %s", r.SrcAddr)
+func handleCreatePermissionRequest(req Request, stunMsg *stun.Message) error {
+ req.Log.Debugf("Received CreatePermission from %s", req.SrcAddr)
- a := r.AllocationManager.GetAllocation(&allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+ alloc := req.AllocationManager.GetAllocation(&allocation.FiveTuple{
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
})
- if a == nil {
- return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
+ if alloc == nil {
+ return fmt.Errorf("%w %v:%v", errNoAllocationFound, req.SrcAddr, req.Conn.LocalAddr())
}
- messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodCreatePermission)
+ messageIntegrity, hasAuth, err := authenticateRequest(req, stunMsg, stun.MethodCreatePermission)
if !hasAuth {
return err
}
addCount := 0
- if err := m.ForEach(stun.AttrXORPeerAddress, func(m *stun.Message) error {
+ if err := stunMsg.ForEach(stun.AttrXORPeerAddress, func(m *stun.Message) error {
var peerAddress proto.PeerAddress
if err := peerAddress.GetFrom(m); err != nil {
return err
}
- if err := r.AllocationManager.GrantPermission(r.SrcAddr, peerAddress.IP); err != nil {
- r.Log.Infof("permission denied for client %s to peer %s", r.SrcAddr, peerAddress.IP)
+ if err := req.AllocationManager.GrantPermission(req.SrcAddr, peerAddress.IP); err != nil {
+ req.Log.Infof("permission denied for client %s to peer %s", req.SrcAddr, peerAddress.IP)
+
return err
}
- r.Log.Debugf("Adding permission for %s", fmt.Sprintf("%s:%d",
+ req.Log.Debugf("Adding permission for %s", fmt.Sprintf("%s:%d",
peerAddress.IP, peerAddress.Port))
- a.AddPermission(allocation.NewPermission(
+ alloc.AddPermission(allocation.NewPermission(
&net.UDPAddr{
IP: peerAddress.IP,
Port: peerAddress.Port,
},
- r.Log,
+ req.Log,
))
addCount++
+
return nil
}); err != nil {
addCount = 0
@@ -267,115 +312,131 @@ func handleCreatePermissionRequest(r Request, m *stun.Message) error {
respClass = stun.ClassErrorResponse
}
- return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodCreatePermission, respClass), []stun.Setter{messageIntegrity}...)...)
+ return buildAndSend(
+ req.Conn,
+ req.SrcAddr,
+ buildMsg(stunMsg.TransactionID, stun.NewType(stun.MethodCreatePermission, respClass),
+ []stun.Setter{messageIntegrity}...)...,
+ )
}
-func handleSendIndication(r Request, m *stun.Message) error {
- r.Log.Debugf("Received SendIndication from %s", r.SrcAddr)
- a := r.AllocationManager.GetAllocation(&allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+func handleSendIndication(req Request, stunMsg *stun.Message) error {
+ req.Log.Debugf("Received SendIndication from %s", req.SrcAddr)
+ alloc := req.AllocationManager.GetAllocation(&allocation.FiveTuple{
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
})
- if a == nil {
- return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
+ if alloc == nil {
+ return fmt.Errorf("%w %v:%v", errNoAllocationFound, req.SrcAddr, req.Conn.LocalAddr())
}
dataAttr := proto.Data{}
- if err := dataAttr.GetFrom(m); err != nil {
+ if err := dataAttr.GetFrom(stunMsg); err != nil {
return err
}
peerAddress := proto.PeerAddress{}
- if err := peerAddress.GetFrom(m); err != nil {
+ if err := peerAddress.GetFrom(stunMsg); err != nil {
return err
}
msgDst := &net.UDPAddr{IP: peerAddress.IP, Port: peerAddress.Port}
- if perm := a.GetPermission(msgDst); perm == nil {
+ if perm := alloc.GetPermission(msgDst); perm == nil {
return fmt.Errorf("%w: %v", errNoPermission, msgDst)
}
- l, err := a.RelaySocket.WriteTo(dataAttr, msgDst)
+ l, err := alloc.RelaySocket.WriteTo(dataAttr, msgDst)
if l != len(dataAttr) {
return fmt.Errorf("%w %d != %d (expected) err: %v", errShortWrite, l, len(dataAttr), err) //nolint:errorlint
}
+
return err
}
-func handleChannelBindRequest(r Request, m *stun.Message) error {
- r.Log.Debugf("Received ChannelBindRequest from %s", r.SrcAddr)
+func handleChannelBindRequest(req Request, stunMsg *stun.Message) error {
+ req.Log.Debugf("Received ChannelBindRequest from %s", req.SrcAddr)
- a := r.AllocationManager.GetAllocation(&allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+ alloc := req.AllocationManager.GetAllocation(&allocation.FiveTuple{
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
})
- if a == nil {
- return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
+ if alloc == nil {
+ return fmt.Errorf("%w %v:%v", errNoAllocationFound, req.SrcAddr, req.Conn.LocalAddr())
}
- badRequestMsg := buildMsg(m.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest})
+ badRequestMsg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(stun.MethodChannelBind, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest},
+ )
- messageIntegrity, hasAuth, err := authenticateRequest(r, m, stun.MethodChannelBind)
+ messageIntegrity, hasAuth, err := authenticateRequest(req, stunMsg, stun.MethodChannelBind)
if !hasAuth {
return err
}
var channel proto.ChannelNumber
- if err = channel.GetFrom(m); err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err = channel.GetFrom(stunMsg); err != nil {
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
peerAddr := proto.PeerAddress{}
- if err = peerAddr.GetFrom(m); err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err = peerAddr.GetFrom(stunMsg); err != nil {
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
- if err = r.AllocationManager.GrantPermission(r.SrcAddr, peerAddr.IP); err != nil {
- r.Log.Infof("permission denied for client %s to peer %s", r.SrcAddr, peerAddr.IP)
+ if err = req.AllocationManager.GrantPermission(req.SrcAddr, peerAddr.IP); err != nil {
+ req.Log.Infof("permission denied for client %s to peer %s", req.SrcAddr, peerAddr.IP)
- unauthorizedRequestMsg := buildMsg(m.TransactionID,
+ unauthorizedRequestMsg := buildMsg(stunMsg.TransactionID,
stun.NewType(stun.MethodChannelBind, stun.ClassErrorResponse),
&stun.ErrorCodeAttribute{Code: stun.CodeUnauthorized})
- return buildAndSendErr(r.Conn, r.SrcAddr, err, unauthorizedRequestMsg...)
+
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, unauthorizedRequestMsg...)
}
- r.Log.Debugf("Binding channel %d to %s", channel, peerAddr)
- err = a.AddChannelBind(allocation.NewChannelBind(
+ req.Log.Debugf("Binding channel %d to %s", channel, peerAddr)
+ err = alloc.AddChannelBind(allocation.NewChannelBind(
channel,
&net.UDPAddr{IP: peerAddr.IP, Port: peerAddr.Port},
- r.Log,
- ), r.ChannelBindTimeout)
+ req.Log,
+ ), req.ChannelBindTimeout)
if err != nil {
- return buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ return buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
- return buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassSuccessResponse), []stun.Setter{messageIntegrity}...)...)
+ return buildAndSend(
+ req.Conn,
+ req.SrcAddr,
+ buildMsg(stunMsg.TransactionID, stun.NewType(stun.MethodChannelBind, stun.ClassSuccessResponse),
+ []stun.Setter{messageIntegrity}...)...,
+ )
}
-func handleChannelData(r Request, c *proto.ChannelData) error {
- r.Log.Debugf("Received ChannelData from %s", r.SrcAddr)
+func handleChannelData(req Request, channelData *proto.ChannelData) error {
+ req.Log.Debugf("Received ChannelData from %s", req.SrcAddr)
- a := r.AllocationManager.GetAllocation(&allocation.FiveTuple{
- SrcAddr: r.SrcAddr,
- DstAddr: r.Conn.LocalAddr(),
+ alloc := req.AllocationManager.GetAllocation(&allocation.FiveTuple{
+ SrcAddr: req.SrcAddr,
+ DstAddr: req.Conn.LocalAddr(),
Protocol: allocation.UDP,
})
- if a == nil {
- return fmt.Errorf("%w %v:%v", errNoAllocationFound, r.SrcAddr, r.Conn.LocalAddr())
+ if alloc == nil {
+ return fmt.Errorf("%w %v:%v", errNoAllocationFound, req.SrcAddr, req.Conn.LocalAddr())
}
- channel := a.GetChannelByNumber(c.Number)
+ channel := alloc.GetChannelByNumber(channelData.Number)
if channel == nil {
- return fmt.Errorf("%w %x", errNoSuchChannelBind, uint16(c.Number))
+ return fmt.Errorf("%w %x", errNoSuchChannelBind, uint16(channelData.Number))
}
- l, err := a.RelaySocket.WriteTo(c.Data, channel.Peer)
+ l, err := alloc.RelaySocket.WriteTo(channelData.Data, channel.Peer)
if err != nil {
return fmt.Errorf("%w: %s", errFailedWriteSocket, err.Error())
- } else if l != len(c.Data) {
- return fmt.Errorf("%w %d != %d (expected)", errShortWrite, l, len(c.Data))
+ } else if l != len(channelData.Data) {
+ return fmt.Errorf("%w %d != %d (expected)", errShortWrite, l, len(channelData.Data))
}
return nil
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/util.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/util.go
index 7c01d3297..a16bf439f 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/util.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/internal/server/util.go
@@ -14,7 +14,8 @@ import (
)
const (
- maximumAllocationLifetime = time.Hour // See: https://tools.ietf.org/html/rfc5766#section-6.2 defines 3600 seconds recommendation
+ // See: https://tools.ietf.org/html/rfc5766#section-6.2 defines 3600 seconds recommendation.
+ maximumAllocationLifetime = time.Hour
)
func buildAndSend(conn net.PacketConn, dst net.Addr, attrs ...stun.Setter) error {
@@ -30,71 +31,90 @@ func buildAndSend(conn net.PacketConn, dst net.Addr, attrs ...stun.Setter) error
return err
}
-// Send a STUN packet and return the original error to the caller
+// Send a STUN packet and return the original error to the caller.
func buildAndSendErr(conn net.PacketConn, dst net.Addr, err error, attrs ...stun.Setter) error {
if sendErr := buildAndSend(conn, dst, attrs...); sendErr != nil {
err = fmt.Errorf("%w %v %v", errFailedToSendError, sendErr, err) //nolint:errorlint
}
+
return err
}
-func buildMsg(transactionID [stun.TransactionIDSize]byte, msgType stun.MessageType, additional ...stun.Setter) []stun.Setter {
+func buildMsg(
+ transactionID [stun.TransactionIDSize]byte,
+ msgType stun.MessageType,
+ additional ...stun.Setter,
+) []stun.Setter {
return append([]stun.Setter{&stun.Message{TransactionID: transactionID}, msgType}, additional...)
}
-func authenticateRequest(r Request, m *stun.Message, callingMethod stun.Method) (stun.MessageIntegrity, bool, error) {
+func authenticateRequest(req Request, stunMsg *stun.Message, callingMethod stun.Method) (
+ stun.MessageIntegrity,
+ bool,
+ error,
+) {
respondWithNonce := func(responseCode stun.ErrorCode) (stun.MessageIntegrity, bool, error) {
- nonce, err := r.NonceHash.Generate()
+ nonce, err := req.NonceHash.Generate()
if err != nil {
return nil, false, err
}
- return nil, false, buildAndSend(r.Conn, r.SrcAddr, buildMsg(m.TransactionID,
+ return nil, false, buildAndSend(req.Conn, req.SrcAddr, buildMsg(stunMsg.TransactionID,
stun.NewType(callingMethod, stun.ClassErrorResponse),
&stun.ErrorCodeAttribute{Code: responseCode},
stun.NewNonce(nonce),
- stun.NewRealm(r.Realm),
+ stun.NewRealm(req.Realm),
)...)
}
- if !m.Contains(stun.AttrMessageIntegrity) {
+ if !stunMsg.Contains(stun.AttrMessageIntegrity) {
return respondWithNonce(stun.CodeUnauthorized)
}
nonceAttr := &stun.Nonce{}
usernameAttr := &stun.Username{}
realmAttr := &stun.Realm{}
- badRequestMsg := buildMsg(m.TransactionID, stun.NewType(callingMethod, stun.ClassErrorResponse), &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest})
+ badRequestMsg := buildMsg(
+ stunMsg.TransactionID,
+ stun.NewType(callingMethod, stun.ClassErrorResponse),
+ &stun.ErrorCodeAttribute{Code: stun.CodeBadRequest},
+ )
// No Auth handler is set, server is running in STUN only mode
- // Respond with 400 so clients don't retry
- if r.AuthHandler == nil {
- sendErr := buildAndSend(r.Conn, r.SrcAddr, badRequestMsg...)
+ // Respond with 400 so clients don't retry.
+ if req.AuthHandler == nil {
+ sendErr := buildAndSend(req.Conn, req.SrcAddr, badRequestMsg...)
+
return nil, false, sendErr
}
- if err := nonceAttr.GetFrom(m); err != nil {
- return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err := nonceAttr.GetFrom(stunMsg); err != nil {
+ return nil, false, buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
- // Assert Nonce is signed and is not expired
- if err := r.NonceHash.Validate(nonceAttr.String()); err != nil {
+ // Assert Nonce is signed and is not expired.
+ if err := req.NonceHash.Validate(nonceAttr.String()); err != nil {
return respondWithNonce(stun.CodeStaleNonce)
}
- if err := realmAttr.GetFrom(m); err != nil {
- return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
- } else if err := usernameAttr.GetFrom(m); err != nil {
- return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err := realmAttr.GetFrom(stunMsg); err != nil {
+ return nil, false, buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
+ } else if err := usernameAttr.GetFrom(stunMsg); err != nil {
+ return nil, false, buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
- ourKey, ok := r.AuthHandler(usernameAttr.String(), realmAttr.String(), r.SrcAddr)
+ ourKey, ok := req.AuthHandler(usernameAttr.String(), realmAttr.String(), req.SrcAddr)
if !ok {
- return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, fmt.Errorf("%w %s", errNoSuchUser, usernameAttr.String()), badRequestMsg...)
+ return nil, false, buildAndSendErr(
+ req.Conn,
+ req.SrcAddr,
+ fmt.Errorf("%w %s", errNoSuchUser, usernameAttr.String()),
+ badRequestMsg...,
+ )
}
- if err := stun.MessageIntegrity(ourKey).Check(m); err != nil {
- return nil, false, buildAndSendErr(r.Conn, r.SrcAddr, err, badRequestMsg...)
+ if err := stun.MessageIntegrity(ourKey).Check(stunMsg); err != nil {
+ return nil, false, buildAndSendErr(req.Conn, req.SrcAddr, err, badRequestMsg...)
}
return stun.MessageIntegrity(ourKey), true, nil
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/lt_cred.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/lt_cred.go
index 42466c381..65576be28 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/lt_cred.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/lt_cred.go
@@ -3,7 +3,7 @@
package turn
-import ( //nolint:gci
+import (
"crypto/hmac"
"crypto/sha1" //nolint:gosec,gci
"encoding/base64"
@@ -15,20 +15,26 @@ import ( //nolint:gci
"github.com/pion/logging"
)
-// GenerateLongTermCredentials can be used to create credentials valid for [duration] time
+// GenerateLongTermCredentials can be used to create credentials valid for [duration] time.
func GenerateLongTermCredentials(sharedSecret string, duration time.Duration) (string, string, error) {
t := time.Now().Add(duration).Unix()
username := strconv.FormatInt(t, 10)
password, err := longTermCredentials(username, sharedSecret)
+
return username, password, err
}
-// GenerateLongTermTURNRESTCredentials can be used to create credentials valid for [duration] time
-func GenerateLongTermTURNRESTCredentials(sharedSecret string, user string, duration time.Duration) (string, string, error) {
+// GenerateLongTermTURNRESTCredentials can be used to create credentials valid for [duration] time.
+func GenerateLongTermTURNRESTCredentials(sharedSecret string, user string, duration time.Duration) (
+ string,
+ string,
+ error,
+) {
t := time.Now().Add(duration).Unix()
timestamp := strconv.FormatInt(t, 10)
username := timestamp + ":" + user
password, err := longTermCredentials(username, sharedSecret)
+
return username, password, err
}
@@ -39,31 +45,38 @@ func longTermCredentials(username string, sharedSecret string) (string, error) {
return "", err // Not sure if this will ever happen
}
password := mac.Sum(nil)
+
return base64.StdEncoding.EncodeToString(password), nil
}
// NewLongTermAuthHandler returns a turn.AuthAuthHandler used with Long Term (or Time Windowed) Credentials.
// See: https://datatracker.ietf.org/doc/html/rfc8489#section-9.2
-func NewLongTermAuthHandler(sharedSecret string, l logging.LeveledLogger) AuthHandler {
- if l == nil {
- l = logging.NewDefaultLoggerFactory().NewLogger("turn")
+// .
+func NewLongTermAuthHandler(sharedSecret string, logger logging.LeveledLogger) AuthHandler {
+ if logger == nil {
+ logger = logging.NewDefaultLoggerFactory().NewLogger("turn")
}
+
return func(username, realm string, srcAddr net.Addr) (key []byte, ok bool) {
- l.Tracef("Authentication username=%q realm=%q srcAddr=%v", username, realm, srcAddr)
+ logger.Tracef("Authentication username=%q realm=%q srcAddr=%v", username, realm, srcAddr)
t, err := strconv.Atoi(username)
if err != nil {
- l.Errorf("Invalid time-windowed username %q", username)
+ logger.Errorf("Invalid time-windowed username %q", username)
+
return nil, false
}
if int64(t) < time.Now().Unix() {
- l.Errorf("Expired time-windowed username %q", username)
+ logger.Errorf("Expired time-windowed username %q", username)
+
return nil, false
}
password, err := longTermCredentials(username, sharedSecret)
if err != nil {
- l.Error(err.Error())
+ logger.Error(err.Error())
+
return nil, false
}
+
return GenerateAuthKey(username, realm, password), true
}
}
@@ -74,27 +87,32 @@ func NewLongTermAuthHandler(sharedSecret string, l logging.LeveledLogger) AuthHa
//
// The supported format of is timestamp:username, where username is an arbitrary user id and the
// timestamp specifies the expiry of the credential.
-func LongTermTURNRESTAuthHandler(sharedSecret string, l logging.LeveledLogger) AuthHandler {
- if l == nil {
- l = logging.NewDefaultLoggerFactory().NewLogger("turn")
+func LongTermTURNRESTAuthHandler(sharedSecret string, logger logging.LeveledLogger) AuthHandler {
+ if logger == nil {
+ logger = logging.NewDefaultLoggerFactory().NewLogger("turn")
}
+
return func(username, realm string, srcAddr net.Addr) (key []byte, ok bool) {
- l.Tracef("Authentication username=%q realm=%q srcAddr=%v\n", username, realm, srcAddr)
+ logger.Tracef("Authentication username=%q realm=%q srcAddr=%v", username, realm, srcAddr)
timestamp := strings.Split(username, ":")[0]
t, err := strconv.Atoi(timestamp)
if err != nil {
- l.Errorf("Invalid time-windowed username %q", username)
+ logger.Errorf("Invalid time-windowed username %q", username)
+
return nil, false
}
if int64(t) < time.Now().Unix() {
- l.Errorf("Expired time-windowed username %q", username)
+ logger.Errorf("Expired time-windowed username %q", username)
+
return nil, false
}
password, err := longTermCredentials(username, sharedSecret)
if err != nil {
- l.Error(err.Error())
+ logger.Error(err.Error())
+
return nil, false
}
+
return GenerateAuthKey(username, realm, password), true
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_none.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_none.go
index b0974010c..f60b10308 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_none.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_none.go
@@ -12,7 +12,7 @@ import (
"github.com/pion/transport/v3/stdnet"
)
-// RelayAddressGeneratorNone returns the listener with no modifications
+// RelayAddressGeneratorNone returns the listener with no modifications.
type RelayAddressGeneratorNone struct {
// Address is passed to Listen/ListenPacket when creating the Relay
Address string
@@ -20,7 +20,7 @@ type RelayAddressGeneratorNone struct {
Net transport.Net
}
-// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured
+// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured.
func (r *RelayAddressGeneratorNone) Validate() error {
if r.Net == nil {
var err error
@@ -38,8 +38,13 @@ func (r *RelayAddressGeneratorNone) Validate() error {
}
}
-// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port to populate the allocation response with
-func (r *RelayAddressGeneratorNone) AllocatePacketConn(network string, requestedPort int) (net.PacketConn, net.Addr, error) {
+// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port
+// to populate the allocation response with.
+func (r *RelayAddressGeneratorNone) AllocatePacketConn(network string, requestedPort int) (
+ net.PacketConn,
+ net.Addr,
+ error,
+) {
conn, err := r.Net.ListenPacket(network, r.Address+":"+strconv.Itoa(requestedPort))
if err != nil {
return nil, nil, err
@@ -48,7 +53,8 @@ func (r *RelayAddressGeneratorNone) AllocatePacketConn(network string, requested
return conn, conn.LocalAddr(), nil
}
-// AllocateConn generates a new Conn to receive traffic on and the IP/Port to populate the allocation response with
+// AllocateConn generates a new Conn to receive traffic on and the IP/Port
+// to populate the allocation response with.
func (r *RelayAddressGeneratorNone) AllocateConn(string, int) (net.Conn, net.Addr, error) {
return nil, nil, errTODO
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_range.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_range.go
index d87a57f9f..5b3c42953 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_range.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_range.go
@@ -35,7 +35,7 @@ type RelayAddressGeneratorPortRange struct {
Net transport.Net
}
-// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured
+// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured.
func (r *RelayAddressGeneratorPortRange) Validate() error {
if r.Net == nil {
var err error
@@ -67,24 +67,30 @@ func (r *RelayAddressGeneratorPortRange) Validate() error {
}
}
-// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port to populate the allocation response with
-func (r *RelayAddressGeneratorPortRange) AllocatePacketConn(network string, requestedPort int) (net.PacketConn, net.Addr, error) {
+// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port
+// to populate the allocation response with.
+func (r *RelayAddressGeneratorPortRange) AllocatePacketConn(
+ network string,
+ requestedPort int,
+) (net.PacketConn, net.Addr, error) {
if requestedPort != 0 {
conn, err := r.Net.ListenPacket(network, fmt.Sprintf("%s:%d", r.Address, requestedPort))
if err != nil {
return nil, nil, err
}
+
relayAddr, ok := conn.LocalAddr().(*net.UDPAddr)
if !ok {
return nil, nil, errNilConn
}
relayAddr.IP = r.RelayAddress
+
return conn, relayAddr, nil
}
for try := 0; try < r.MaxRetries; try++ {
- port := r.MinPort + uint16(r.Rand.Intn(int((r.MaxPort+1)-r.MinPort)))
+ port := r.MinPort + uint16(r.Rand.Intn(int((r.MaxPort+1)-r.MinPort))) // nolint:gosec // G115 false positive
conn, err := r.Net.ListenPacket(network, fmt.Sprintf("%s:%d", r.Address, port))
if err != nil {
continue
@@ -96,13 +102,15 @@ func (r *RelayAddressGeneratorPortRange) AllocatePacketConn(network string, requ
}
relayAddr.IP = r.RelayAddress
+
return conn, relayAddr, nil
}
return nil, nil, errMaxRetriesExceeded
}
-// AllocateConn generates a new Conn to receive traffic on and the IP/Port to populate the allocation response with
+// AllocateConn generates a new Conn to receive traffic on and the IP/Port
+// to populate the allocation response with.
func (r *RelayAddressGeneratorPortRange) AllocateConn(string, int) (net.Conn, net.Addr, error) {
return nil, nil, errTODO
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_static.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_static.go
index 39c687779..12ea5f254 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_static.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/relay_address_generator_static.go
@@ -13,7 +13,7 @@ import (
)
// RelayAddressGeneratorStatic can be used to return static IP address each time a relay is created.
-// This can be used when you have a single static IP address that you want to use
+// This can be used when you have a single static IP address that you want to use.
type RelayAddressGeneratorStatic struct {
// RelayAddress is the IP returned to the user when the relay is created
RelayAddress net.IP
@@ -24,7 +24,7 @@ type RelayAddressGeneratorStatic struct {
Net transport.Net
}
-// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured
+// Validate is called on server startup and confirms the RelayAddressGenerator is properly configured.
func (r *RelayAddressGeneratorStatic) Validate() error {
if r.Net == nil {
var err error
@@ -44,8 +44,12 @@ func (r *RelayAddressGeneratorStatic) Validate() error {
}
}
-// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port to populate the allocation response with
-func (r *RelayAddressGeneratorStatic) AllocatePacketConn(network string, requestedPort int) (net.PacketConn, net.Addr, error) {
+// AllocatePacketConn generates a new PacketConn to receive traffic on and the IP/Port
+// to populate the allocation response with.
+func (r *RelayAddressGeneratorStatic) AllocatePacketConn(
+ network string,
+ requestedPort int,
+) (net.PacketConn, net.Addr, error) {
conn, err := r.Net.ListenPacket(network, r.Address+":"+strconv.Itoa(requestedPort))
if err != nil {
return nil, nil, err
@@ -62,7 +66,8 @@ func (r *RelayAddressGeneratorStatic) AllocatePacketConn(network string, request
return conn, relayAddr, nil
}
-// AllocateConn generates a new Conn to receive traffic on and the IP/Port to populate the allocation response with
+// AllocateConn generates a new Conn to receive traffic on and the IP/Port
+// to populate the allocation response with.
func (r *RelayAddressGeneratorStatic) AllocateConn(string, int) (net.Conn, net.Addr, error) {
return nil, nil, errTODO
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server.go
index 3b58938ff..5d03643db 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server.go
@@ -20,7 +20,7 @@ const (
defaultInboundMTU = 1600
)
-// Server is an instance of the Pion TURN Server
+// Server is an instance of the Pion TURN Server.
type Server struct {
log logging.LeveledLogger
authHandler AuthHandler
@@ -34,10 +34,8 @@ type Server struct {
inboundMTU int
}
-// NewServer creates the Pion TURN server
-//
-//nolint:gocognit
-func NewServer(config ServerConfig) (*Server, error) {
+// NewServer creates the Pion TURN server.
+func NewServer(config ServerConfig) (*Server, error) { //nolint:gocognit,cyclop
if err := config.validate(); err != nil {
return nil, err
}
@@ -57,7 +55,7 @@ func NewServer(config ServerConfig) (*Server, error) {
return nil, err
}
- s := &Server{
+ server := &Server{
log: loggerFactory.NewLogger("turn"),
authHandler: config.AuthHandler,
realm: config.Realm,
@@ -68,53 +66,56 @@ func NewServer(config ServerConfig) (*Server, error) {
inboundMTU: mtu,
}
- if s.channelBindTimeout == 0 {
- s.channelBindTimeout = proto.DefaultLifetime
+ if server.channelBindTimeout == 0 {
+ server.channelBindTimeout = proto.DefaultLifetime
}
- for _, cfg := range s.packetConnConfigs {
- am, err := s.createAllocationManager(cfg.RelayAddressGenerator, cfg.PermissionHandler)
+ for _, cfg := range server.packetConnConfigs {
+ am, err := server.createAllocationManager(cfg.RelayAddressGenerator, cfg.PermissionHandler)
if err != nil {
return nil, fmt.Errorf("failed to create AllocationManager: %w", err)
}
go func(cfg PacketConnConfig, am *allocation.Manager) {
- s.readLoop(cfg.PacketConn, am)
+ server.readLoop(cfg.PacketConn, am)
if err := am.Close(); err != nil {
- s.log.Errorf("Failed to close AllocationManager: %s", err)
+ server.log.Errorf("Failed to close AllocationManager: %s", err)
}
}(cfg, am)
}
- for _, cfg := range s.listenerConfigs {
- am, err := s.createAllocationManager(cfg.RelayAddressGenerator, cfg.PermissionHandler)
+ for _, cfg := range server.listenerConfigs {
+ am, err := server.createAllocationManager(cfg.RelayAddressGenerator, cfg.PermissionHandler)
if err != nil {
return nil, fmt.Errorf("failed to create AllocationManager: %w", err)
}
go func(cfg ListenerConfig, am *allocation.Manager) {
- s.readListener(cfg.Listener, am)
+ server.readListener(cfg.Listener, am)
if err := am.Close(); err != nil {
- s.log.Errorf("Failed to close AllocationManager: %s", err)
+ server.log.Errorf("Failed to close AllocationManager: %s", err)
}
}(cfg, am)
}
- return s, nil
+ return server, nil
}
-// AllocationCount returns the number of active allocations. It can be used to drain the server before closing
+// AllocationCount returns the number of active allocations.
+// It can be used to drain the server before closing.
func (s *Server) AllocationCount() int {
allocs := 0
for _, am := range s.allocationManagers {
allocs += am.AllocationCount()
}
+
return allocs
}
-// Close stops the TURN Server. It cleans up any associated state and closes all connections it is managing
+// Close stops the TURN Server.
+// It cleans up any associated state and closes all connections it is managing.
func (s *Server) Close() error {
var errors []error
@@ -147,6 +148,7 @@ func (s *Server) readListener(l net.Listener, am *allocation.Manager) {
conn, err := l.Accept()
if err != nil {
s.log.Debugf("Failed to accept: %s", err)
+
return
}
@@ -179,7 +181,10 @@ func (n *nilAddressGenerator) AllocateConn(string, int) (net.Conn, net.Addr, err
return nil, nil, errRelayAddressGeneratorNil
}
-func (s *Server) createAllocationManager(addrGenerator RelayAddressGenerator, handler PermissionHandler) (*allocation.Manager, error) {
+func (s *Server) createAllocationManager(
+ addrGenerator RelayAddressGenerator,
+ handler PermissionHandler,
+) (*allocation.Manager, error) {
if handler == nil {
handler = DefaultPermissionHandler
}
@@ -202,21 +207,23 @@ func (s *Server) createAllocationManager(addrGenerator RelayAddressGenerator, ha
return am, err
}
-func (s *Server) readLoop(p net.PacketConn, allocationManager *allocation.Manager) {
+func (s *Server) readLoop(conn net.PacketConn, allocationManager *allocation.Manager) {
buf := make([]byte, s.inboundMTU)
for {
- n, addr, err := p.ReadFrom(buf)
+ n, addr, err := conn.ReadFrom(buf)
switch {
case err != nil:
s.log.Debugf("Exit read loop on error: %s", err)
+
return
case n >= s.inboundMTU:
s.log.Debugf("Read bytes exceeded MTU, packet is possibly truncated")
+
continue
}
if err := server.HandleRequest(server.Request{
- Conn: p,
+ Conn: conn,
SrcAddr: addr,
Buff: buf[:n],
Log: s.log,
@@ -226,7 +233,7 @@ func (s *Server) readLoop(p net.PacketConn, allocationManager *allocation.Manage
ChannelBindTimeout: s.channelBindTimeout,
NonceHash: s.nonceHash,
}); err != nil {
- s.log.Errorf("Failed to handle datagram: %v", err)
+ s.log.Debugf("Failed to handle datagram: %v", err)
}
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server_config.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server_config.go
index eaa7a2581..8f2761403 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server_config.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/server_config.go
@@ -34,12 +34,13 @@ type RelayAddressGenerator interface {
// of NATs that comply with [RFC4787], see https://tools.ietf.org/html/rfc5766#section-2.3.
type PermissionHandler func(clientAddr net.Addr, peerIP net.IP) (ok bool)
-// DefaultPermissionHandler is convince function that grants permission to all peers
+// DefaultPermissionHandler is convince function that grants permission to all peers.
func DefaultPermissionHandler(net.Addr, net.IP) (ok bool) {
return true
}
-// PacketConnConfig is a single net.PacketConn to listen/write on. This will be used for UDP listeners
+// PacketConnConfig is a single net.PacketConn to listen/write on.
+// This will be used for UDP listeners.
type PacketConnConfig struct {
PacketConn net.PacketConn
@@ -67,7 +68,8 @@ func (c *PacketConnConfig) validate() error {
return nil
}
-// ListenerConfig is a single net.Listener to accept connections on. This will be used for TCP, TLS and DTLS listeners
+// ListenerConfig is a single net.Listener to accept connections on.
+// This will be used for TCP, TLS and DTLS listeners.
type ListenerConfig struct {
Listener net.Listener
@@ -93,18 +95,20 @@ func (c *ListenerConfig) validate() error {
return c.RelayAddressGenerator.Validate()
}
-// AuthHandler is a callback used to handle incoming auth requests, allowing users to customize Pion TURN with custom behavior
+// AuthHandler is a callback used to handle incoming auth requests,
+// allowing users to customize Pion TURN with custom behavior.
type AuthHandler func(username, realm string, srcAddr net.Addr) (key []byte, ok bool)
-// GenerateAuthKey is a convenience function to easily generate keys in the format used by AuthHandler
+// GenerateAuthKey is a convenience function to easily generate keys in the format used by AuthHandler.
func GenerateAuthKey(username, realm, password string) []byte {
// #nosec
h := md5.New()
- fmt.Fprint(h, strings.Join([]string{username, realm, password}, ":"))
+ fmt.Fprint(h, strings.Join([]string{username, realm, password}, ":")) // nolint: errcheck
+
return h.Sum(nil)
}
-// ServerConfig configures the Pion TURN Server
+// ServerConfig configures the Pion TURN Server.
type ServerConfig struct {
// PacketConnConfigs and ListenerConfigs are a list of all the turn listeners
// Each listener can have custom behavior around the creation of Relays
@@ -117,7 +121,8 @@ type ServerConfig struct {
// Realm sets the realm for this server
Realm string
- // AuthHandler is a callback used to handle incoming auth requests, allowing users to customize Pion TURN with custom behavior
+ // AuthHandler is a callback used to handle incoming auth requests,
+ // allowing users to customize Pion TURN with custom behavior
AuthHandler AuthHandler
// ChannelBindTimeout sets the lifetime of channel binding. Defaults to 10 minutes.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/stun_conn.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/stun_conn.go
index 57543544a..fd1f1ae6e 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/stun_conn.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/turn/v4/stun_conn.go
@@ -20,7 +20,7 @@ var (
// STUNConn wraps a net.Conn and implements
// net.PacketConn by being STUN aware and
-// packetizing the stream
+// packetizing the stream.
type STUNConn struct {
nextConn net.Conn
buff []byte
@@ -36,92 +36,93 @@ const (
)
// Given a buffer give the last offset of the TURN frame
-// If the buffer isn't a valid STUN or ChannelData packet
-// or the length doesn't match return false
-func consumeSingleTURNFrame(p []byte) (int, error) {
+// If the buffer isn't a valid STUN or ChannelData packet,
+// or the length doesn't match return false.
+func consumeSingleTURNFrame(b []byte) (int, error) {
// Too short to determine if ChannelData or STUN
- if len(p) < 9 {
+ if len(b) < 9 {
return 0, errIncompleteTURNFrame
}
var datagramSize uint16
switch {
- case stun.IsMessage(p):
- datagramSize = binary.BigEndian.Uint16(p[2:4]) + stunHeaderSize
- case proto.ChannelNumber(binary.BigEndian.Uint16(p[0:2])).Valid():
- datagramSize = binary.BigEndian.Uint16(p[channelDataNumberSize:channelDataHeaderSize])
+ case stun.IsMessage(b):
+ datagramSize = binary.BigEndian.Uint16(b[2:4]) + stunHeaderSize
+ case proto.ChannelNumber(binary.BigEndian.Uint16(b[0:2])).Valid():
+ datagramSize = binary.BigEndian.Uint16(b[channelDataNumberSize:channelDataHeaderSize])
if paddingOverflow := (datagramSize + channelDataPadding) % channelDataPadding; paddingOverflow != 0 {
datagramSize = (datagramSize + channelDataPadding) - paddingOverflow
}
datagramSize += channelDataHeaderSize
- case len(p) < stunHeaderSize:
+ case len(b) < stunHeaderSize:
return 0, errIncompleteTURNFrame
default:
return 0, errInvalidTURNFrame
}
- if len(p) < int(datagramSize) {
+ if len(b) < int(datagramSize) {
return 0, errIncompleteTURNFrame
}
return int(datagramSize), nil
}
-// ReadFrom implements ReadFrom from net.PacketConn
-func (s *STUNConn) ReadFrom(p []byte) (n int, addr net.Addr, err error) {
+// ReadFrom implements ReadFrom from net.PacketConn.
+func (s *STUNConn) ReadFrom(payload []byte) (n int, addr net.Addr, err error) {
// First pass any buffered data from previous reads
n, err = consumeSingleTURNFrame(s.buff)
if errors.Is(err, errInvalidTURNFrame) {
return 0, nil, err
} else if err == nil {
- copy(p, s.buff[:n])
+ copy(payload, s.buff[:n])
s.buff = s.buff[n:]
return n, s.nextConn.RemoteAddr(), nil
}
// Then read from the nextConn, appending to our buff
- n, err = s.nextConn.Read(p)
+ n, err = s.nextConn.Read(payload)
if err != nil {
return 0, nil, err
}
- s.buff = append(s.buff, append([]byte{}, p[:n]...)...)
- return s.ReadFrom(p)
+ s.buff = append(s.buff, append([]byte{}, payload[:n]...)...)
+
+ return s.ReadFrom(payload)
}
-// WriteTo implements WriteTo from net.PacketConn
-func (s *STUNConn) WriteTo(p []byte, _ net.Addr) (n int, err error) {
- return s.nextConn.Write(p)
+// WriteTo implements WriteTo from net.PacketConn.
+func (s *STUNConn) WriteTo(payload []byte, _ net.Addr) (n int, err error) {
+ return s.nextConn.Write(payload)
}
-// Close implements Close from net.PacketConn
+// Close implements Close from net.PacketConn.
func (s *STUNConn) Close() error {
return s.nextConn.Close()
}
-// LocalAddr implements LocalAddr from net.PacketConn
+// LocalAddr implements LocalAddr from net.PacketConn.
func (s *STUNConn) LocalAddr() net.Addr {
return s.nextConn.LocalAddr()
}
-// SetDeadline implements SetDeadline from net.PacketConn
+// SetDeadline implements SetDeadline from net.PacketConn.
func (s *STUNConn) SetDeadline(t time.Time) error {
return s.nextConn.SetDeadline(t)
}
-// SetReadDeadline implements SetReadDeadline from net.PacketConn
+// SetReadDeadline implements SetReadDeadline from net.PacketConn.
func (s *STUNConn) SetReadDeadline(t time.Time) error {
return s.nextConn.SetReadDeadline(t)
}
-// SetWriteDeadline implements SetWriteDeadline from net.PacketConn
+// SetWriteDeadline implements SetWriteDeadline from net.PacketConn.
func (s *STUNConn) SetWriteDeadline(t time.Time) error {
return s.nextConn.SetWriteDeadline(t)
}
-// NewSTUNConn creates a STUNConn
+// NewSTUNConn creates a STUNConn.
func NewSTUNConn(nextConn net.Conn) *STUNConn {
return &STUNConn{nextConn: nextConn}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/.golangci.yml b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/.golangci.yml
index 120faf29b..59edee274 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/.golangci.yml
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/.golangci.yml
@@ -41,6 +41,12 @@ linters-settings:
- w io.Writer
- r io.Reader
- b []byte
+ revive:
+ rules:
+ # Prefer 'any' type alias over 'interface{}' for Go 1.18+ compatibility
+ - name: use-any
+ severity: warning
+ disabled: false
linters:
enable:
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/atomicbool.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/atomicbool.go
deleted file mode 100644
index 846289eca..000000000
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/atomicbool.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The Pion community
-// SPDX-License-Identifier: MIT
-
-package webrtc
-
-import "sync/atomic"
-
-type atomicBool struct {
- val int32
-}
-
-func (b *atomicBool) set(value bool) { // nolint: unparam
- var i int32
- if value {
- i = 1
- }
-
- atomic.StoreInt32(&(b.val), i)
-}
-
-func (b *atomicBool) get() bool {
- return atomic.LoadInt32(&(b.val)) != 0
-}
-
-func (b *atomicBool) swap(value bool) bool {
- var i int32
- if value {
- i = 1
- }
-
- return atomic.SwapInt32(&(b.val), i) != 0
-}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/datachannel_js.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/datachannel_js.go
index add07b697..26ff02cdf 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/datachannel_js.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/datachannel_js.go
@@ -48,7 +48,7 @@ func (d *DataChannel) OnOpen(f func()) {
oldHandler := d.onOpenHandler
defer oldHandler.Release()
}
- onOpenHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onOpenHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -63,7 +63,7 @@ func (d *DataChannel) OnClose(f func()) {
oldHandler := d.onCloseHandler
defer oldHandler.Release()
}
- onCloseHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onCloseHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -78,7 +78,7 @@ func (d *DataChannel) OnClosing(f func()) {
oldHandler := d.onClosingHandler
defer oldHandler.Release()
}
- onClosingHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onClosingHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -91,7 +91,7 @@ func (d *DataChannel) OnError(f func(err error)) {
oldHandler := d.onErrorHandler
defer oldHandler.Release()
}
- onErrorHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onErrorHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
event := args[0]
errorObj := event.Get("error")
// FYI RTCError has some extra properties, e.g. `errorDetail`:
@@ -111,7 +111,7 @@ func (d *DataChannel) OnMessage(f func(msg DataChannelMessage)) {
oldHandler := d.onMessageHandler
defer oldHandler.Release()
}
- onMessageHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onMessageHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
// pion/webrtc/projects/15
data := args[0].Get("data")
go func() {
@@ -300,7 +300,7 @@ func (d *DataChannel) OnBufferedAmountLow(f func()) {
oldHandler := d.onBufferedAmountLow
defer oldHandler.Release()
}
- onBufferedAmountLow := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onBufferedAmountLow := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -336,7 +336,7 @@ func valueToDataChannelMessage(val js.Value) DataChannelMessage {
// channel to signal when reading is done.
reader := js.Global().Get("FileReader").New()
doneChan := make(chan struct{})
- reader.Call("addEventListener", "loadend", js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ reader.Call("addEventListener", "loadend", js.FuncOf(func(this js.Value, args []js.Value) any {
go func() {
// Signal that the FileReader is done reading/loading by sending through
// the doneChan.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/errors.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/errors.go
index 539422913..fc5ea2cdb 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/errors.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/errors.go
@@ -248,7 +248,7 @@ var (
errRTPSenderRIDCollision = errors.New("Sender cannot encoding due to RID collision")
errRTPSenderNoTrackForRID = errors.New("Sender does not have track for RID")
- errRTPTransceiverCannotChangeMid = errors.New("errRTPSenderTrackNil")
+ errRTPTransceiverCannotChangeMid = errors.New("cannot change transceiver mid")
errRTPTransceiverSetSendingInvalidState = errors.New("invalid state change in RTPTransceiver.setSending")
errRTPTransceiverCodecUnsupported = errors.New("unsupported codec type by this transceiver")
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver.go
index 32a368541..7be341aed 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver.go
@@ -18,7 +18,7 @@ import (
type ICEServer struct {
URLs []string `json:"urls"`
Username string `json:"username,omitempty"`
- Credential interface{} `json:"credential,omitempty"`
+ Credential any `json:"credential,omitempty"`
CredentialType ICECredentialType `json:"credentialType,omitempty"`
}
@@ -74,8 +74,8 @@ func (s ICEServer) urls() ([]*stun.URI, error) { //nolint:cyclop
return urls, nil
}
-func iceserverUnmarshalUrls(val interface{}) (*[]string, error) {
- s, ok := val.([]interface{})
+func iceserverUnmarshalUrls(val any) (*[]string, error) {
+ s, ok := val.([]any)
if !ok {
return nil, errInvalidICEServer
}
@@ -90,8 +90,8 @@ func iceserverUnmarshalUrls(val interface{}) (*[]string, error) {
return &out, nil
}
-func iceserverUnmarshalOauth(val interface{}) (*OAuthCredential, error) {
- c, ok := val.(map[string]interface{})
+func iceserverUnmarshalOauth(val any) (*OAuthCredential, error) {
+ c, ok := val.(map[string]any)
if !ok {
return nil, errInvalidICEServer
}
@@ -110,7 +110,7 @@ func iceserverUnmarshalOauth(val interface{}) (*OAuthCredential, error) {
}, nil
}
-func (s *ICEServer) iceserverUnmarshalFields(fields map[string]interface{}) error { //nolint:cyclop
+func (s *ICEServer) iceserverUnmarshalFields(fields map[string]any) error { //nolint:cyclop
if val, ok := fields["urls"]; ok {
u, err := iceserverUnmarshalUrls(val)
if err != nil {
@@ -160,12 +160,12 @@ func (s *ICEServer) iceserverUnmarshalFields(fields map[string]interface{}) erro
// UnmarshalJSON parses the JSON-encoded data and stores the result.
func (s *ICEServer) UnmarshalJSON(b []byte) error {
- var tmp interface{}
+ var tmp any
err := json.Unmarshal(b, &tmp)
if err != nil {
return err
}
- if m, ok := tmp.(map[string]interface{}); ok {
+ if m, ok := tmp.(map[string]any); ok {
return s.iceserverUnmarshalFields(m)
}
@@ -174,7 +174,7 @@ func (s *ICEServer) UnmarshalJSON(b []byte) error {
// MarshalJSON returns the JSON encoding.
func (s ICEServer) MarshalJSON() ([]byte, error) {
- m := make(map[string]interface{})
+ m := make(map[string]any)
m["urls"] = s.URLs
if s.Username != "" {
m["username"] = s.Username
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver_js.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver_js.go
index 2f293dde0..f121349d0 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver_js.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/iceserver_js.go
@@ -18,7 +18,7 @@ type ICEServer struct {
URLs []string
Username string
// Note: TURN is not supported in the WASM bindings yet
- Credential interface{}
+ Credential any
CredentialType ICECredentialType
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/interceptor.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/interceptor.go
index d2df622f9..5d7dea4c8 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/interceptor.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/interceptor.go
@@ -10,6 +10,7 @@ import (
"sync/atomic"
"github.com/pion/interceptor"
+ "github.com/pion/interceptor/pkg/flexfec"
"github.com/pion/interceptor/pkg/nack"
"github.com/pion/interceptor/pkg/report"
"github.com/pion/interceptor/pkg/rfc8888"
@@ -160,6 +161,41 @@ func ConfigureSimulcastExtensionHeaders(mediaEngine *MediaEngine) error {
)
}
+// ConfigureFlexFEC03 registers flexfec-03 codec with provided payloadType in mediaEngine
+// and adds corresponding interceptor to the registry.
+// Note that this function should be called before any other interceptor that modifies RTP packets
+// (i.e. TWCCHeaderExtensionSender) is added to the registry, so that packets generated by flexfec
+// interceptor are not modified.
+func ConfigureFlexFEC03(
+ payloadType PayloadType,
+ mediaEngine *MediaEngine,
+ interceptorRegistry *interceptor.Registry,
+ options ...flexfec.FecOption,
+) error {
+ codecFEC := RTPCodecParameters{
+ RTPCodecCapability: RTPCodecCapability{
+ MimeType: MimeTypeFlexFEC03,
+ ClockRate: 90000,
+ SDPFmtpLine: "repair-window=10000000",
+ RTCPFeedback: nil,
+ },
+ PayloadType: payloadType,
+ }
+
+ if err := mediaEngine.RegisterCodec(codecFEC, RTPCodecTypeVideo); err != nil {
+ return err
+ }
+
+ generator, err := flexfec.NewFecInterceptor(options...)
+ if err != nil {
+ return err
+ }
+
+ interceptorRegistry.Add(generator)
+
+ return nil
+}
+
type interceptorToTrackLocalWriter struct{ interceptor atomic.Value } // interceptor.RTPWriter }
func (i *interceptorToTrackLocalWriter) WriteRTP(header *rtp.Header, payload []byte) (int, error) {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/js_utils.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/js_utils.go
index 7e7b5e190..ee3120b65 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/js_utils.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/js_utils.go
@@ -19,7 +19,7 @@ func awaitPromise(promise js.Value) (js.Value, error) {
resultsChan := make(chan js.Value)
errChan := make(chan js.Error)
- thenFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ thenFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
go func() {
resultsChan <- args[0]
}()
@@ -27,7 +27,7 @@ func awaitPromise(promise js.Value) (js.Value, error) {
})
defer thenFunc.Release()
- catchFunc := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ catchFunc := js.FuncOf(func(this js.Value, args []js.Value) any {
go func() {
errChan <- js.Error{args[0]}
}()
@@ -75,7 +75,7 @@ func uint8ToValueOrUndefined(val uint8) js.Value {
return js.ValueOf(val)
}
-func interfaceToValueOrUndefined(val interface{}) js.Value {
+func interfaceToValueOrUndefined(val any) js.Value {
if val == nil {
return js.Undefined()
}
@@ -140,7 +140,7 @@ func boolPointerToValue(val *bool) js.Value {
}
func stringsToValue(strings []string) js.Value {
- val := make([]interface{}, len(strings))
+ val := make([]any, len(strings))
for i, s := range strings {
val[i] = s
}
@@ -155,7 +155,7 @@ func stringEnumToValueOrUndefined(s string) js.Value {
}
// Converts the return value of recover() to an error.
-func recoveryToError(e interface{}) error {
+func recoveryToError(e any) error {
switch e := e.(type) {
case error:
return e
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/operations.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/operations.go
index 3e65f1357..a86850f57 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/operations.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/operations.go
@@ -6,6 +6,7 @@ package webrtc
import (
"container/list"
"sync"
+ "sync/atomic"
)
// Operation is a function.
@@ -17,13 +18,13 @@ type operations struct {
busyCh chan struct{}
ops *list.List
- updateNegotiationNeededFlagOnEmptyChain *atomicBool
+ updateNegotiationNeededFlagOnEmptyChain *atomic.Bool
onNegotiationNeeded func()
isClosed bool
}
func newOperations(
- updateNegotiationNeededFlagOnEmptyChain *atomicBool,
+ updateNegotiationNeededFlagOnEmptyChain *atomic.Bool,
onNegotiationNeeded func(),
) *operations {
return &operations{
@@ -150,9 +151,9 @@ func (o *operations) start() {
fn()
fn = o.pop()
}
- if !o.updateNegotiationNeededFlagOnEmptyChain.get() {
+ if !o.updateNegotiationNeededFlagOnEmptyChain.Load() {
return
}
- o.updateNegotiationNeededFlagOnEmptyChain.set(false)
+ o.updateNegotiationNeededFlagOnEmptyChain.Store(false)
o.onNegotiationNeeded()
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/package.json b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/package.json
index f58d23972..642ff8406 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/package.json
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/package.json
@@ -3,7 +3,7 @@
"repository": "git@github.com:pion/webrtc.git",
"private": true,
"devDependencies": {
- "@roamhq/wrtc": "^0.8.0"
+ "@roamhq/wrtc": "^0.9.0"
},
"dependencies": {
"request": "2.88.2"
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection.go
index a2d1a7afb..50b05cd05 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection.go
@@ -55,12 +55,12 @@ type PeerConnection struct {
idpLoginURL *string
- isClosed *atomicBool
+ isClosed *atomic.Bool
isGracefullyClosingOrClosed bool
isCloseDone chan struct{}
isGracefulCloseDone chan struct{}
- isNegotiationNeeded *atomicBool
- updateNegotiationNeededFlagOnEmptyChain *atomicBool
+ isNegotiationNeeded *atomic.Bool
+ updateNegotiationNeededFlagOnEmptyChain *atomic.Bool
lastOffer string
lastAnswer string
@@ -124,11 +124,11 @@ func (api *API) NewPeerConnection(configuration Configuration) (*PeerConnection,
Certificates: []Certificate{},
ICECandidatePoolSize: 0,
},
- isClosed: &atomicBool{},
+ isClosed: &atomic.Bool{},
isCloseDone: make(chan struct{}),
isGracefulCloseDone: make(chan struct{}),
- isNegotiationNeeded: &atomicBool{},
- updateNegotiationNeededFlagOnEmptyChain: &atomicBool{},
+ isNegotiationNeeded: &atomic.Bool{},
+ updateNegotiationNeededFlagOnEmptyChain: &atomic.Bool{},
lastOffer: "",
lastAnswer: "",
greaterMid: -1,
@@ -296,7 +296,7 @@ func (pc *PeerConnection) onNegotiationNeeded() {
// 4.7.3.1 If the length of connection.[[Operations]] is not 0, then set
// connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] to true, and abort these steps.
if !pc.ops.IsEmpty() {
- pc.updateNegotiationNeededFlagOnEmptyChain.set(true)
+ pc.updateNegotiationNeededFlagOnEmptyChain.Store(true)
return
}
@@ -306,7 +306,7 @@ func (pc *PeerConnection) onNegotiationNeeded() {
// https://www.w3.org/TR/webrtc/#dfn-update-the-negotiation-needed-flag
func (pc *PeerConnection) negotiationNeededOp() {
// 4.7.3.2.1 If connection.[[IsClosed]] is true, abort these steps.
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return
}
@@ -314,7 +314,7 @@ func (pc *PeerConnection) negotiationNeededOp() {
// then set connection.[[UpdateNegotiationNeededFlagOnEmptyChain]] to
// true, and abort these steps.
if !pc.ops.IsEmpty() {
- pc.updateNegotiationNeededFlagOnEmptyChain.set(true)
+ pc.updateNegotiationNeededFlagOnEmptyChain.Store(true)
return
}
@@ -328,18 +328,18 @@ func (pc *PeerConnection) negotiationNeededOp() {
// clear the negotiation-needed flag by setting connection.[[NegotiationNeeded]]
// to false, and abort these steps.
if !pc.checkNegotiationNeeded() {
- pc.isNegotiationNeeded.set(false)
+ pc.isNegotiationNeeded.Store(false)
return
}
// 4.7.3.2.5 If connection.[[NegotiationNeeded]] is already true, abort these steps.
- if pc.isNegotiationNeeded.get() {
+ if pc.isNegotiationNeeded.Load() {
return
}
// 4.7.3.2.6 Set connection.[[NegotiationNeeded]] to true.
- pc.isNegotiationNeeded.set(true)
+ pc.isNegotiationNeeded.Store(true)
// 4.7.3.2.7 Fire an event named negotiationneeded at connection.
if handler, ok := pc.onNegotiationNeededHandler.Load().(func()); ok && handler != nil {
@@ -513,7 +513,7 @@ func (pc *PeerConnection) onConnectionStateChange(cs PeerConnectionState) {
// SetConfiguration updates the configuration of this PeerConnection object.
func (pc *PeerConnection) SetConfiguration(configuration Configuration) error { //nolint:gocognit,cyclop
// https://www.w3.org/TR/webrtc/#dom-rtcpeerconnection-setconfiguration (step #2)
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -623,7 +623,7 @@ func (pc *PeerConnection) CreateOffer(options *OfferOptions) (SessionDescription
switch {
case useIdentity:
return SessionDescription{}, errIdentityProviderNotImplemented
- case pc.isClosed.get():
+ case pc.isClosed.Load():
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -763,7 +763,7 @@ func (pc *PeerConnection) updateConnectionState(
connectionState := PeerConnectionStateNew
switch {
// The RTCPeerConnection object's [[IsClosed]] slot is true.
- case pc.isClosed.get():
+ case pc.isClosed.Load():
connectionState = PeerConnectionStateClosed
// Any of the RTCIceTransports or RTCDtlsTransports are in a "failed" state.
@@ -844,7 +844,7 @@ func (pc *PeerConnection) CreateAnswer(*AnswerOptions) (SessionDescription, erro
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrNoRemoteDescription}
case useIdentity:
return SessionDescription{}, errIdentityProviderNotImplemented
- case pc.isClosed.get():
+ case pc.isClosed.Load():
return SessionDescription{}, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
case pc.signalingState.Get() != SignalingStateHaveRemoteOffer &&
pc.signalingState.Get() != SignalingStateHaveLocalPranswer:
@@ -891,7 +891,7 @@ func (pc *PeerConnection) CreateAnswer(*AnswerOptions) (SessionDescription, erro
//nolint:gocognit,cyclop
func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeOp) error {
switch {
- case pc.isClosed.get():
+ case pc.isClosed.Load():
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
case NewSDPType(sd.Type.String()) == SDPTypeUnknown:
return &rtcerr.TypeError{
@@ -995,7 +995,7 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
if err == nil {
pc.signalingState.Set(nextState)
if pc.signalingState.Get() == SignalingStateStable {
- pc.isNegotiationNeeded.set(false)
+ pc.isNegotiationNeeded.Store(false)
pc.mu.Lock()
pc.onNegotiationNeeded()
pc.mu.Unlock()
@@ -1010,7 +1010,7 @@ func (pc *PeerConnection) setDescription(sd *SessionDescription, op stateChangeO
//
//nolint:cyclop
func (pc *PeerConnection) SetLocalDescription(desc SessionDescription) error {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -1081,7 +1081,7 @@ func (pc *PeerConnection) LocalDescription() *SessionDescription {
//
//nolint:gocognit,gocyclo,cyclop,maintidx
func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -1700,7 +1700,10 @@ func (pc *PeerConnection) handleIncomingSSRC(rtpStream io.Reader, ssrc SSRC) err
// If a SSRC already exists in the RemoteDescription don't perform heuristics upon it
for _, track := range trackDetailsFromSDP(pc.log, remoteDescription.parsed) {
- if track.repairSsrc != nil && ssrc == *track.repairSsrc {
+ if track.rtxSsrc != nil && ssrc == *track.rtxSsrc {
+ return nil
+ }
+ if track.fecSsrc != nil && ssrc == *track.fecSsrc {
return nil
}
for _, trackSsrc := range track.ssrcs {
@@ -1883,7 +1886,7 @@ func (pc *PeerConnection) undeclaredRTPMediaProcessor() { //nolint:cyclop
return
}
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
if err = srtpReadStream.Close(); err != nil {
pc.log.Warnf("Failed to close RTP stream %v", err)
}
@@ -2073,7 +2076,7 @@ func (pc *PeerConnection) GetTransceivers() []*RTPTransceiver {
//
//nolint:cyclop
func (pc *PeerConnection) AddTrack(track TrackLocal) (*RTPSender, error) {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -2115,7 +2118,7 @@ func (pc *PeerConnection) AddTrack(track TrackLocal) (*RTPSender, error) {
// RemoveTrack removes a Track from the PeerConnection.
func (pc *PeerConnection) RemoveTrack(sender *RTPSender) (err error) {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -2183,7 +2186,7 @@ func (pc *PeerConnection) AddTransceiverFromKind(
kind RTPCodecType,
init ...RTPTransceiverInit,
) (t *RTPTransceiver, err error) {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -2228,7 +2231,7 @@ func (pc *PeerConnection) AddTransceiverFromTrack(
track TrackLocal,
init ...RTPTransceiverInit,
) (t *RTPTransceiver, err error) {
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -2256,7 +2259,7 @@ func (pc *PeerConnection) AddTransceiverFromTrack(
//nolint:cyclop
func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelInit) (*DataChannel, error) {
// https://w3c.github.io/webrtc-pc/#peer-to-peer-data-api (Step #2)
- if pc.isClosed.get() {
+ if pc.isClosed.Load() {
return nil, &rtcerr.InvalidStateError{Err: ErrConnectionClosed}
}
@@ -2377,7 +2380,7 @@ func (pc *PeerConnection) close(shouldGracefullyClose bool) error { //nolint:cyc
// some overlapping close cases when both normal and graceful close are used
// that should be idempotent, but be cautioned when writing new close behavior
// to preserve this property.
- isAlreadyClosingOrClosed := pc.isClosed.swap(true)
+ isAlreadyClosingOrClosed := pc.isClosed.Swap(true)
isAlreadyGracefullyClosingOrClosed := pc.isGracefullyClosingOrClosed
if shouldGracefullyClose && !isAlreadyGracefullyClosingOrClosed {
pc.isGracefullyClosingOrClosed = true
@@ -2665,7 +2668,7 @@ func (pc *PeerConnection) startTransports(
}
pc.dtlsTransport.internalOnCloseHandler = func() {
- if pc.isClosed.get() || pc.api.settingEngine.disableCloseByDTLS {
+ if pc.isClosed.Load() || pc.api.settingEngine.disableCloseByDTLS {
return
}
@@ -2718,7 +2721,7 @@ func (pc *PeerConnection) generateUnmatchedSDP(
if err != nil {
return nil, err
}
- desc.Attributes = append(desc.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS*"})
+ desc.Attributes = append(desc.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS *"})
iceParams, err := pc.iceGatherer.GetLocalParameters()
if err != nil {
@@ -2811,7 +2814,7 @@ func (pc *PeerConnection) generateMatchedSDP(
if err != nil {
return nil, err
}
- desc.Attributes = append(desc.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS*"})
+ desc.Attributes = append(desc.Attributes, sdp.Attribute{Key: sdp.AttrKeyMsidSemantic, Value: "WMS *"})
iceParams, err := pc.iceGatherer.GetLocalParameters()
if err != nil {
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection_js.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection_js.go
index c7e968ca2..c332930bc 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection_js.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/peerconnection_js.go
@@ -71,7 +71,7 @@ func (pc *PeerConnection) OnSignalingStateChange(f func(SignalingState)) {
oldHandler := pc.onSignalingStateChangeHandler
defer oldHandler.Release()
}
- onSignalingStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onSignalingStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
state := newSignalingState(args[0].String())
go f(state)
return js.Undefined()
@@ -87,7 +87,7 @@ func (pc *PeerConnection) OnDataChannel(f func(*DataChannel)) {
oldHandler := pc.onDataChannelHandler
defer oldHandler.Release()
}
- onDataChannelHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onDataChannelHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
// pion/webrtc/projects/15
// This reference to the underlying DataChannel doesn't know
// about any other references to the same DataChannel. This might result in
@@ -112,7 +112,7 @@ func (pc *PeerConnection) OnNegotiationNeeded(f func()) {
oldHandler := pc.onNegotiationNeededHandler
defer oldHandler.Release()
}
- onNegotiationNeededHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onNegotiationNeededHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -127,7 +127,7 @@ func (pc *PeerConnection) OnICEConnectionStateChange(f func(ICEConnectionState))
oldHandler := pc.onICEConnectionStateChangeHandler
defer oldHandler.Release()
}
- onICEConnectionStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onICEConnectionStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
connectionState := NewICEConnectionState(pc.underlying.Get("iceConnectionState").String())
go f(connectionState)
return js.Undefined()
@@ -143,7 +143,7 @@ func (pc *PeerConnection) OnConnectionStateChange(f func(PeerConnectionState)) {
oldHandler := pc.onConnectionStateChangeHandler
defer oldHandler.Release()
}
- onConnectionStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onConnectionStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
connectionState := newPeerConnectionState(pc.underlying.Get("connectionState").String())
go f(connectionState)
return js.Undefined()
@@ -335,7 +335,7 @@ func (pc *PeerConnection) OnICECandidate(f func(candidate *ICECandidate)) {
oldHandler := pc.onICECandidateHandler
defer oldHandler.Release()
}
- onICECandidateHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onICECandidateHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
candidate := valueToICECandidate(args[0].Get("candidate"))
if candidate == nil && pc.onGatherCompleteHandler != nil {
go pc.onGatherCompleteHandler()
@@ -355,7 +355,7 @@ func (pc *PeerConnection) OnICEGatheringStateChange(f func()) {
oldHandler := pc.onICEGatheringStateChangeHandler
defer oldHandler.Release()
}
- onICEGatheringStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ onICEGatheringStateChangeHandler := js.FuncOf(func(this js.Value, args []js.Value) any {
go f()
return js.Undefined()
})
@@ -545,7 +545,7 @@ func (pc *PeerConnection) SCTP() *SCTPTransport {
// through to the JavaScript WebRTC API. Any zero values are converted to
// js.Undefined(), which will result in the default value being used.
func configurationToValue(configuration Configuration) js.Value {
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"iceServers": iceServersToValue(configuration.ICEServers),
"iceTransportPolicy": stringEnumToValueOrUndefined(configuration.ICETransportPolicy.String()),
"bundlePolicy": stringEnumToValueOrUndefined(configuration.BundlePolicy.String()),
@@ -562,7 +562,7 @@ func iceServersToValue(iceServers []ICEServer) js.Value {
if len(iceServers) == 0 {
return js.Undefined()
}
- maps := make([]interface{}, len(iceServers))
+ maps := make([]any, len(iceServers))
for i, server := range iceServers {
maps[i] = iceServerToValue(server)
}
@@ -570,7 +570,7 @@ func iceServersToValue(iceServers []ICEServer) js.Value {
}
func oauthCredentialToValue(o OAuthCredential) js.Value {
- out := map[string]interface{}{
+ out := map[string]any{
"MACKey": o.MACKey,
"AccessToken": o.AccessToken,
}
@@ -578,7 +578,7 @@ func oauthCredentialToValue(o OAuthCredential) js.Value {
}
func iceServerToValue(server ICEServer) js.Value {
- out := map[string]interface{}{
+ out := map[string]any{
"urls": stringsToValue(server.URLs), // required
}
if server.Username != "" {
@@ -624,7 +624,7 @@ func valueToICEServers(iceServersValue js.Value) []ICEServer {
return iceServers
}
-func valueToICECredential(iceCredentialValue js.Value) interface{} {
+func valueToICECredential(iceCredentialValue js.Value) any {
if iceCredentialValue.IsNull() || iceCredentialValue.IsUndefined() {
return nil
}
@@ -704,7 +704,7 @@ func sessionDescriptionToValue(desc *SessionDescription) js.Value {
if desc == nil {
return js.Undefined()
}
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"type": desc.Type.String(),
"sdp": desc.SDP,
})
@@ -724,7 +724,7 @@ func offerOptionsToValue(offerOptions *OfferOptions) js.Value {
if offerOptions == nil {
return js.Undefined()
}
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"iceRestart": offerOptions.ICERestart,
"voiceActivityDetection": offerOptions.VoiceActivityDetection,
})
@@ -734,13 +734,13 @@ func answerOptionsToValue(answerOptions *AnswerOptions) js.Value {
if answerOptions == nil {
return js.Undefined()
}
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"voiceActivityDetection": answerOptions.VoiceActivityDetection,
})
}
func iceCandidateInitToValue(candidate ICECandidateInit) js.Value {
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"candidate": candidate.Candidate,
"sdpMid": stringPointerToValue(candidate.SDPMid),
"sdpMLineIndex": uint16PointerToValue(candidate.SDPMLineIndex),
@@ -754,7 +754,7 @@ func dataChannelInitToValue(options *DataChannelInit) js.Value {
}
maxPacketLifeTime := uint16PointerToValue(options.MaxPacketLifeTime)
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"ordered": boolPointerToValue(options.Ordered),
"maxPacketLifeTime": maxPacketLifeTime,
// See https://bugs.chromium.org/p/chromium/issues/detail?id=696681
@@ -768,7 +768,7 @@ func dataChannelInitToValue(options *DataChannelInit) js.Value {
}
func rtpTransceiverInitInitToValue(init RTPTransceiverInit) js.Value {
- return js.ValueOf(map[string]interface{}{
+ return js.ValueOf(map[string]any{
"direction": init.Direction.String(),
})
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/h265reader.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/h265reader.go
new file mode 100644
index 000000000..5131ac68b
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/h265reader.go
@@ -0,0 +1,232 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+// Package h265reader implements a H265/HEVC Annex-B Reader
+package h265reader
+
+import (
+ "bytes"
+ "errors"
+ "io"
+)
+
+// H265Reader reads data from stream and constructs h265 nal units.
+type H265Reader struct {
+ stream io.Reader
+ nalBuffer []byte
+ countOfConsecutiveZeroBytes int
+ nalPrefixParsed bool
+ readBuffer []byte
+ tmpReadBuf []byte
+}
+
+var (
+ errNilReader = errors.New("stream is nil")
+ errDataIsNotH265Stream = errors.New("data is not a H265/HEVC bitstream")
+)
+
+// NewReader creates new H265Reader.
+func NewReader(in io.Reader) (*H265Reader, error) {
+ if in == nil {
+ return nil, errNilReader
+ }
+
+ reader := &H265Reader{
+ stream: in,
+ nalBuffer: make([]byte, 0),
+ nalPrefixParsed: false,
+ readBuffer: make([]byte, 0),
+ tmpReadBuf: make([]byte, 4096),
+ }
+
+ return reader, nil
+}
+
+// NAL H.265/HEVC Network Abstraction Layer.
+type NAL struct {
+ PictureOrderCount uint32
+
+ /* NAL Unit header https://datatracker.ietf.org/doc/html/rfc7798#section-1.1.4
+ +---------------+---------------+
+ |0|1|2|3|4|5|6|7|0|1|2|3|4|5|6|7|
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |F| Type | LayerId | TID |
+ +-------------+-----------------+
+ */
+ ForbiddenZeroBit bool
+ NalUnitType NalUnitType
+ LayerID uint8
+ TemporalIDPlus1 uint8
+
+ Data []byte // header bytes + rbsp
+}
+
+func (reader *H265Reader) read(numToRead int) (data []byte, e error) {
+ for len(reader.readBuffer) < numToRead {
+ n, err := reader.stream.Read(reader.tmpReadBuf)
+ if err != nil {
+ return nil, err
+ }
+ if n == 0 {
+ break
+ }
+ reader.readBuffer = append(reader.readBuffer, reader.tmpReadBuf[0:n]...)
+ }
+ var numShouldRead int
+ if numToRead <= len(reader.readBuffer) {
+ numShouldRead = numToRead
+ } else {
+ numShouldRead = len(reader.readBuffer)
+ }
+ data = reader.readBuffer[0:numShouldRead]
+ reader.readBuffer = reader.readBuffer[numShouldRead:]
+
+ return data, nil
+}
+
+func (reader *H265Reader) bitStreamStartsWithH265Prefix() (prefixLength int, e error) {
+ nalPrefix3Bytes := []byte{0, 0, 1}
+ nalPrefix4Bytes := []byte{0, 0, 0, 1}
+
+ prefixBuffer, e := reader.read(4)
+ if e != nil {
+ return prefixLength, e
+ }
+
+ n := len(prefixBuffer)
+
+ if n == 0 {
+ return 0, io.EOF
+ }
+
+ if n < 3 {
+ return 0, errDataIsNotH265Stream
+ }
+
+ nalPrefix3BytesFound := bytes.Equal(nalPrefix3Bytes, prefixBuffer[:3])
+ if n == 3 {
+ if nalPrefix3BytesFound {
+ return 0, io.EOF
+ }
+
+ return 0, errDataIsNotH265Stream
+ }
+
+ // n == 4
+ if nalPrefix3BytesFound {
+ reader.nalBuffer = append(reader.nalBuffer, prefixBuffer[3])
+
+ return 3, nil
+ }
+
+ nalPrefix4BytesFound := bytes.Equal(nalPrefix4Bytes, prefixBuffer)
+ if nalPrefix4BytesFound {
+ return 4, nil
+ }
+
+ return 0, errDataIsNotH265Stream
+}
+
+// NextNAL reads from stream and returns then next NAL,
+// and an error if there is incomplete frame data.
+// Returns all nil values when no more NALs are available.
+func (reader *H265Reader) NextNAL() (*NAL, error) {
+ if !reader.nalPrefixParsed {
+ _, err := reader.bitStreamStartsWithH265Prefix()
+ if err != nil {
+ return nil, err
+ }
+
+ reader.nalPrefixParsed = true
+ }
+
+ for {
+ buffer, err := reader.read(1)
+ if err != nil {
+ break
+ }
+
+ n := len(buffer)
+
+ if n != 1 {
+ break
+ }
+ readByte := buffer[0]
+ nalFound := reader.processByte(readByte)
+ if nalFound {
+ naluType := NalUnitType((reader.nalBuffer[0] & 0x7E) >> 1)
+ if naluType == NalUnitTypePrefixSei || naluType == NalUnitTypeSuffixSei {
+ reader.nalBuffer = nil
+
+ continue
+ }
+
+ break
+ }
+
+ reader.nalBuffer = append(reader.nalBuffer, readByte)
+ }
+
+ if len(reader.nalBuffer) == 0 {
+ return nil, io.EOF
+ }
+
+ nal := newNal(reader.nalBuffer)
+ reader.nalBuffer = nil
+ nal.parseHeader()
+
+ return nal, nil
+}
+
+func (reader *H265Reader) processByte(readByte byte) (nalFound bool) {
+ nalFound = false
+
+ switch readByte {
+ case 0:
+ reader.countOfConsecutiveZeroBytes++
+ case 1:
+ if reader.countOfConsecutiveZeroBytes >= 2 {
+ countOfConsecutiveZeroBytesInPrefix := 2
+ if reader.countOfConsecutiveZeroBytes > 2 {
+ countOfConsecutiveZeroBytesInPrefix = 3
+ }
+
+ if nalUnitLength := len(reader.nalBuffer) - countOfConsecutiveZeroBytesInPrefix; nalUnitLength > 0 {
+ reader.nalBuffer = reader.nalBuffer[0:nalUnitLength]
+ nalFound = true
+ }
+ }
+
+ reader.countOfConsecutiveZeroBytes = 0
+ default:
+ reader.countOfConsecutiveZeroBytes = 0
+ }
+
+ return nalFound
+}
+
+func newNal(data []byte) *NAL {
+ return &NAL{
+ PictureOrderCount: 0,
+ ForbiddenZeroBit: false,
+ NalUnitType: NalUnitTypeTrailN,
+ LayerID: 0,
+ TemporalIDPlus1: 0,
+ Data: data,
+ }
+}
+
+func (h *NAL) parseHeader() {
+ if len(h.Data) < 2 {
+ return
+ }
+
+ // H.265 NAL header is 2 bytes
+ firstByte := h.Data[0]
+ secondByte := h.Data[1]
+
+ h.ForbiddenZeroBit = (firstByte & 0x80) != 0
+ h.NalUnitType = NalUnitType((firstByte & 0x7E) >> 1)
+ h.LayerID = ((firstByte & 0x01) << 5) | ((secondByte & 0xF8) >> 3)
+ h.TemporalIDPlus1 = secondByte & 0x07
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/nalunittype.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/nalunittype.go
new file mode 100644
index 000000000..e0a178bc2
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/h265reader/nalunittype.go
@@ -0,0 +1,115 @@
+// SPDX-FileCopyrightText: 2023 The Pion community
+// SPDX-License-Identifier: MIT
+
+package h265reader
+
+import "strconv"
+
+// NalUnitType is the type of a NAL unit in H.265/HEVC.
+type NalUnitType uint8
+
+// Enums for H.265/HEVC NAL unit types.
+const (
+ // VCL NAL unit types.
+ NalUnitTypeTrailN NalUnitType = 0 // Coded slice segment of a non-TSA, non-STSA trailing picture
+ NalUnitTypeTrailR NalUnitType = 1 // Coded slice segment of a non-TSA, non-STSA trailing picture
+ NalUnitTypeTsaN NalUnitType = 2 // Coded slice segment of a TSA picture
+ NalUnitTypeTsaR NalUnitType = 3 // Coded slice segment of a TSA picture
+ NalUnitTypeStsaN NalUnitType = 4 // Coded slice segment of an STSA picture
+ NalUnitTypeStsaR NalUnitType = 5 // Coded slice segment of an STSA picture
+ NalUnitTypeRadlN NalUnitType = 6 // Coded slice segment of a RADL picture
+ NalUnitTypeRadlR NalUnitType = 7 // Coded slice segment of a RADL picture
+ NalUnitTypeRaslN NalUnitType = 8 // Coded slice segment of a RASL picture
+ NalUnitTypeRaslR NalUnitType = 9 // Coded slice segment of a RASL picture
+ NalUnitTypeBlaWLp NalUnitType = 16 // Coded slice segment of a BLA picture
+ NalUnitTypeBlaWRadl NalUnitType = 17 // Coded slice segment of a BLA picture
+ NalUnitTypeBlaNLp NalUnitType = 18 // Coded slice segment of a BLA picture
+ NalUnitTypeIdrWRadl NalUnitType = 19 // Coded slice segment of an IDR picture
+ NalUnitTypeIdrNLp NalUnitType = 20 // Coded slice segment of an IDR picture
+ NalUnitTypeCraNut NalUnitType = 21 // Coded slice segment of a CRA picture
+
+ // Non-VCL NAL unit types.
+ NalUnitTypeVps NalUnitType = 32 // Video parameter set
+ NalUnitTypeSps NalUnitType = 33 // Sequence parameter set
+ NalUnitTypePps NalUnitType = 34 // Picture parameter set
+ NalUnitTypeAud NalUnitType = 35 // Access unit delimiter
+ NalUnitTypeEos NalUnitType = 36 // End of sequence
+ NalUnitTypeEob NalUnitType = 37 // End of bitstream
+ NalUnitTypeFd NalUnitType = 38 // Filler data
+ NalUnitTypePrefixSei NalUnitType = 39 // Supplemental enhancement information
+ NalUnitTypeSuffixSei NalUnitType = 40 // Supplemental enhancement information
+
+ // Reserved.
+ NalUnitTypeReserved41 NalUnitType = 41
+ NalUnitTypeReserved47 NalUnitType = 47
+ NalUnitTypeUnspec48 NalUnitType = 48
+ NalUnitTypeUnspec63 NalUnitType = 63
+)
+
+func (n *NalUnitType) String() string { //nolint:cyclop
+ var str string
+ switch *n {
+ case NalUnitTypeTrailN:
+ str = "TrailN"
+ case NalUnitTypeTrailR:
+ str = "TrailR"
+ case NalUnitTypeTsaN:
+ str = "TsaN"
+ case NalUnitTypeTsaR:
+ str = "TsaR"
+ case NalUnitTypeStsaN:
+ str = "StsaN"
+ case NalUnitTypeStsaR:
+ str = "StsaR"
+ case NalUnitTypeRadlN:
+ str = "RadlN"
+ case NalUnitTypeRadlR:
+ str = "RadlR"
+ case NalUnitTypeRaslN:
+ str = "RaslN"
+ case NalUnitTypeRaslR:
+ str = "RaslR"
+ case NalUnitTypeBlaWLp:
+ str = "BlaWLp"
+ case NalUnitTypeBlaWRadl:
+ str = "BlaWRadl"
+ case NalUnitTypeBlaNLp:
+ str = "BlaNLp"
+ case NalUnitTypeIdrWRadl:
+ str = "IdrWRadl"
+ case NalUnitTypeIdrNLp:
+ str = "IdrNLp"
+ case NalUnitTypeCraNut:
+ str = "CraNut"
+ case NalUnitTypeVps:
+ str = "VPS"
+ case NalUnitTypeSps:
+ str = "SPS"
+ case NalUnitTypePps:
+ str = "PPS"
+ case NalUnitTypeAud:
+ str = "AUD"
+ case NalUnitTypeEos:
+ str = "EOS"
+ case NalUnitTypeEob:
+ str = "EOB"
+ case NalUnitTypeFd:
+ str = "FD"
+ case NalUnitTypePrefixSei:
+ str = "PrefixSEI"
+ case NalUnitTypeSuffixSei:
+ str = "SuffixSEI"
+ default:
+ switch {
+ case *n >= NalUnitTypeReserved41 && *n <= NalUnitTypeReserved47:
+ str = "Reserved"
+ case *n >= NalUnitTypeUnspec48 && *n <= NalUnitTypeUnspec63:
+ str = "Unspecified"
+ default:
+ str = "Unknown"
+ }
+ }
+ str = str + "(" + strconv.FormatInt(int64(*n), 10) + ")"
+
+ return str
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/media.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/media.go
index f8ee5e382..3da1de7f8 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/media.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/pkg/media/media.go
@@ -17,7 +17,7 @@ type Sample struct {
Duration time.Duration
PacketTimestamp uint32
PrevDroppedPackets uint16
- Metadata interface{}
+ Metadata any
// RTP headers of RTP packets forming this Sample. (Optional)
// Useful for accessing RTP extensions associated to the Sample.
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/rtpreceiver.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/rtpreceiver.go
index 109f88a4a..0e85b2d95 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/rtpreceiver.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/rtpreceiver.go
@@ -61,7 +61,7 @@ type RTPReceiver struct {
tracks []trackStreams
- closed, received chan interface{}
+ closed, received chan any
mu sync.RWMutex
tr *RTPTransceiver
@@ -82,10 +82,10 @@ func (api *API) NewRTPReceiver(kind RTPCodecType, transport *DTLSTransport) (*RT
kind: kind,
transport: transport,
api: api,
- closed: make(chan interface{}),
- received: make(chan interface{}),
+ closed: make(chan any),
+ received: make(chan any),
tracks: []trackStreams{},
- rtxPool: sync.Pool{New: func() interface{} {
+ rtxPool: sync.Pool{New: func() any {
return make([]byte, api.settingEngine.getReceiveMTU())
}},
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/sdp.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/sdp.go
index fa10b6951..6c0b7668b 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/sdp.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/sdp.go
@@ -23,13 +23,14 @@ import (
// trackDetails represents any media source that can be represented in a SDP
// This isn't keyed by SSRC because it also needs to support rid based sources.
type trackDetails struct {
- mid string
- kind RTPCodecType
- streamID string
- id string
- ssrcs []SSRC
- repairSsrc *SSRC
- rids []string
+ mid string
+ kind RTPCodecType
+ streamID string
+ id string
+ ssrcs []SSRC
+ rtxSsrc *SSRC
+ fecSsrc *SSRC
+ rids []string
}
func trackDetailsForSSRC(trackDetails []trackDetails, ssrc SSRC) *trackDetails {
@@ -91,6 +92,7 @@ func trackDetailsFromSDP(
for _, media := range s.MediaDescriptions {
tracksInMediaSection := []trackDetails{}
rtxRepairFlows := map[uint64]uint64{}
+ fecRepairFlows := map[uint64]uint64{}
// Plan B can have multiple tracks in a single media section
streamID := ""
@@ -143,7 +145,35 @@ func trackDetailsFromSDP(
for i := range tracksInMediaSection {
if tracksInMediaSection[i].ssrcs[0] == SSRC(baseSsrc) {
repairSsrc := SSRC(rtxRepairFlow)
- tracksInMediaSection[i].repairSsrc = &repairSsrc
+ tracksInMediaSection[i].rtxSsrc = &repairSsrc
+ }
+ }
+ }
+ } else if split[0] == sdp.SemanticTokenForwardErrorCorrectionFramework {
+ // Similar to above, lines like `a=ssrc-group:FEC-FR aaaaa bbbbb`
+ // means for video ssrc aaaaa, there's a FEC track bbbbb
+ if len(split) == 3 {
+ baseSsrc, err := strconv.ParseUint(split[1], 10, 32)
+ if err != nil {
+ log.Warnf("Failed to parse SSRC: %v", err)
+
+ continue
+ }
+ fecRepairFlow, err := strconv.ParseUint(split[2], 10, 32)
+ if err != nil {
+ log.Warnf("Failed to parse SSRC: %v", err)
+
+ continue
+ }
+ fecRepairFlows[fecRepairFlow] = baseSsrc
+ tracksInMediaSection = filterTrackWithSSRC(
+ tracksInMediaSection,
+ SSRC(fecRepairFlow),
+ ) // Remove if fec was added as track before
+ for i := range tracksInMediaSection {
+ if tracksInMediaSection[i].ssrcs[0] == SSRC(baseSsrc) {
+ repairSsrc := SSRC(fecRepairFlow)
+ tracksInMediaSection[i].fecSsrc = &repairSsrc
}
}
}
@@ -171,6 +201,9 @@ func trackDetailsFromSDP(
if _, ok := rtxRepairFlows[ssrc]; ok {
continue // This ssrc is a RTX repair flow, ignore
}
+ if _, ok := fecRepairFlows[ssrc]; ok {
+ continue // This ssrc is a FEC repair flow, ignore
+ }
if len(split) == 3 && strings.HasPrefix(split[1], "msid:") {
streamID = split[1][len("msid:"):]
@@ -197,7 +230,13 @@ func trackDetailsFromSDP(
for r, baseSsrc := range rtxRepairFlows {
if baseSsrc == ssrc {
repairSsrc := SSRC(r) //nolint:gosec // G115
- trackDetails.repairSsrc = &repairSsrc
+ trackDetails.rtxSsrc = &repairSsrc
+ }
+ }
+ for r, baseSsrc := range fecRepairFlows {
+ if baseSsrc == ssrc {
+ fecSsrc := SSRC(r) //nolint:gosec // G115
+ trackDetails.fecSsrc = &fecSsrc
}
}
@@ -243,8 +282,12 @@ func trackDetailsToRTPReceiveParameters(trackDetails *trackDetails) RTPReceivePa
encodings[i].SSRC = trackDetails.ssrcs[i]
}
- if trackDetails.repairSsrc != nil {
- encodings[i].RTX.SSRC = *trackDetails.repairSsrc
+ if trackDetails.rtxSsrc != nil {
+ encodings[i].RTX.SSRC = *trackDetails.rtxSsrc
+ }
+
+ if trackDetails.fecSsrc != nil {
+ encodings[i].FEC.SSRC = *trackDetails.fecSsrc
}
}
@@ -430,10 +473,26 @@ func addSenderSDP(
sendParameters := sender.GetParameters()
for _, encoding := range sendParameters.Encodings {
if encoding.RTX.SSRC != 0 {
- media = media.WithValueAttribute("ssrc-group", fmt.Sprintf("FID %d %d", encoding.SSRC, encoding.RTX.SSRC))
+ media = media.WithValueAttribute(
+ "ssrc-group",
+ fmt.Sprintf(
+ "%s %d %d",
+ sdp.SemanticTokenFlowIdentification,
+ encoding.SSRC,
+ encoding.RTX.SSRC,
+ ),
+ )
}
if encoding.FEC.SSRC != 0 {
- media = media.WithValueAttribute("ssrc-group", fmt.Sprintf("FEC-FR %d %d", encoding.SSRC, encoding.FEC.SSRC))
+ media = media.WithValueAttribute(
+ "ssrc-group",
+ fmt.Sprintf(
+ "%s %d %d",
+ sdp.SemanticTokenForwardErrorCorrectionFramework,
+ encoding.SSRC,
+ encoding.FEC.SSRC,
+ ),
+ )
}
media = media.WithMediaSource(
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/track_local_static.go b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/track_local_static.go
index 6bac1e1b3..f590d8119 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/track_local_static.go
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/track_local_static.go
@@ -154,7 +154,7 @@ func (s *TrackLocalStaticRTP) Codec() RTPCodecCapability {
// packetPool is a pool of packets used by WriteRTP and Write below
// nolint:gochecknoglobals
var rtpPacketPool = sync.Pool{
- New: func() interface{} {
+ New: func() any {
return &rtp.Packet{}
},
}
@@ -194,6 +194,11 @@ func (s *TrackLocalStaticRTP) writeRTP(packet *rtp.Packet) error {
for _, b := range s.bindings {
packet.Header.SSRC = uint32(b.ssrc)
packet.Header.PayloadType = uint8(b.payloadType)
+ // b.writeStream.WriteRTP below expects header and payload separately, so value of Packet.PaddingSize
+ // would be lost. Copy it to Packet.Header.PaddingSize to avoid that problem.
+ if packet.PaddingSize != 0 && packet.Header.PaddingSize == 0 {
+ packet.Header.PaddingSize = packet.PaddingSize
+ }
if _, err := b.writeStream.WriteRTP(&packet.Header, packet.Payload); err != nil {
writeErrs = append(writeErrs, err)
}
diff --git a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/yarn.lock b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/yarn.lock
index 809d55604..bea781e0a 100644
--- a/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/yarn.lock
+++ b/trunk/3rdparty/srs-bench/vendor/github.com/pion/webrtc/v4/yarn.lock
@@ -1,44 +1,42 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
-# SPDX-FileCopyrightText: 2023 The Pion community
-# SPDX-License-Identifier: MIT
-"@roamhq/wrtc-darwin-arm64@0.8.0":
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc-darwin-arm64/-/wrtc-darwin-arm64-0.8.0.tgz#15057e6b8f57e4d1b7008a9d848b6f2036adbb24"
- integrity sha512-OtV2KWO7zOG3L8TF3KCt9aucynVCD/ww2xeXXgg+FLkya3ca0uzehN8EQJ3BL4tkInksbFJ2ssyu9cehfJ3ZuA==
+"@roamhq/wrtc-darwin-arm64@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc-darwin-arm64/-/wrtc-darwin-arm64-0.9.0.tgz#d3e304dd2d522953635bc372028abf81245e9ab6"
+ integrity sha512-bVbyI3Xm3ZlTPYnKz7gnLkxt1kZ8ZMW5QBwJpF/kS227O71pqUhicX/V5RRGqUmaER3JtXt0naR86ZPDfgTQBg==
-"@roamhq/wrtc-darwin-x64@0.8.0":
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc-darwin-x64/-/wrtc-darwin-x64-0.8.0.tgz#e09137b5a7edf2c2412bc63f1da1893dcaa211fd"
- integrity sha512-VY7Vzt/SDDDCpW//h8GW9bOZrOr8gWXPZVD9473ypl4jyBIoO57yyLbHzd1G0vBUkS6szsHlQCz1WwpI30YL+g==
+"@roamhq/wrtc-darwin-x64@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc-darwin-x64/-/wrtc-darwin-x64-0.9.0.tgz#d879be0fe15f1e3dc9dcd29fb11a7edd73766992"
+ integrity sha512-99FFbFcIIqRR+H4ylkQgbgM8L5dx72hP5/GeJHB2h2f62Mb51bi30KokyOeBKH3X5R8bNi8LKnf7tV8d4kaGlA==
-"@roamhq/wrtc-linux-arm64@0.8.1":
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc-linux-arm64/-/wrtc-linux-arm64-0.8.1.tgz#9a5f3297de44fcec86713d0baefa0594658ab71e"
- integrity sha512-FBJLLazlWkGQUXaokC/rTbrUQbb0CNFYry52fZGstufrGLTWu+g4HcwXdVvxh1tnVtVMvkQGk+mlOL52sCxw0A==
+"@roamhq/wrtc-linux-arm64@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc-linux-arm64/-/wrtc-linux-arm64-0.9.0.tgz#8a335f36c19ebcdf053e939c5cbfc29f40fe0df4"
+ integrity sha512-JUtrPFGvp+/5YWz9L5eW9e4XPQ5lRFQR5/BlGQJQOutrkBYqvME8NvAHKhyNWm+b3Sgk0w6yZ1g1nSttPHFY6g==
-"@roamhq/wrtc-linux-x64@0.8.1":
- version "0.8.1"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc-linux-x64/-/wrtc-linux-x64-0.8.1.tgz#3c5b60ca6cc6ebf5c2389d852f4a101135031da2"
- integrity sha512-I9oWG7b4uvWO1IOR/aF34n+ID6TKVuSs0jd19h5KdhfRtw7FFh9xxuwN9rONPxLVa6fS0q+MCZgAf8Scz89L8Q==
+"@roamhq/wrtc-linux-x64@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc-linux-x64/-/wrtc-linux-x64-0.9.0.tgz#9de97d48bb4443cc25bbd18c523f02a706d9045c"
+ integrity sha512-ve6pIqeadUn6Jypb73A76041zdvGg/Bl0JU+T2+K8Zjw4aASebBFF4NX213dAS5viWUcNULzKV/s2PcpLDCyXQ==
-"@roamhq/wrtc-win32-x64@0.8.0":
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc-win32-x64/-/wrtc-win32-x64-0.8.0.tgz#582e2478df48201d5757b60dcd4b4dcc40a054b7"
- integrity sha512-R2fxl41BLWPiP4eaTHGLzbbVvRjx1mV/OsgINCvawO7Hwz5Zx9I45+Fhrw3hd4n5amIeSG9VIF7Kz8eeTFXTGQ==
+"@roamhq/wrtc-win32-x64@0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc-win32-x64/-/wrtc-win32-x64-0.9.0.tgz#ad212e4305cc71084fab48d6d8c97a0e2360c813"
+ integrity sha512-QoVe5KKP1IjIRGDZfMUJV0OgTCK3noc79P2uuLeR5iJqf+bLcgyNr818ljB7frxPMSZNwWC5eVQTGmclrIIOIg==
-"@roamhq/wrtc@^0.8.0":
- version "0.8.0"
- resolved "https://registry.yarnpkg.com/@roamhq/wrtc/-/wrtc-0.8.0.tgz#03c8c64c3b6a1e6e8965ec6496fa7e97571ae04b"
- integrity sha512-C0V/nqc4/2xzORI5qa4mIeN/8UO3ywN1kInrJ9u6GljFx0D18JMUJEqe8yYHa61RrEeoWN3PKdW++k8TocSx/A==
+"@roamhq/wrtc@^0.9.0":
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/@roamhq/wrtc/-/wrtc-0.9.0.tgz#ef127439c16ef0723f234c56b06378c745fd6cc0"
+ integrity sha512-b61ld6g0hHDh/K1y0Lckxg5HBunaESNW6N23ewviW5IvwBfZiIYPUxQFWxqprMTr/6ODHmw5B2xvqvLyuAL5Xw==
optionalDependencies:
- "@roamhq/wrtc-darwin-arm64" "0.8.0"
- "@roamhq/wrtc-darwin-x64" "0.8.0"
- "@roamhq/wrtc-linux-arm64" "0.8.1"
- "@roamhq/wrtc-linux-x64" "0.8.1"
- "@roamhq/wrtc-win32-x64" "0.8.0"
+ "@roamhq/wrtc-darwin-arm64" "0.9.0"
+ "@roamhq/wrtc-darwin-x64" "0.9.0"
+ "@roamhq/wrtc-linux-arm64" "0.9.0"
+ "@roamhq/wrtc-linux-x64" "0.9.0"
+ "@roamhq/wrtc-win32-x64" "0.9.0"
domexception "^4.0.0"
ajv@^6.5.5:
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/crypto/cryptobyte/asn1.go
index 2492f796a..d25979d9f 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/crypto/cryptobyte/asn1.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/crypto/cryptobyte/asn1.go
@@ -234,7 +234,7 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
// Identifiers with the low five bits set indicate high-tag-number format
// (two or more octets), which we don't support.
if tag&0x1f == 0x1f {
- b.err = fmt.Errorf("cryptobyte: high-tag number identifier octects not supported: 0x%x", tag)
+ b.err = fmt.Errorf("cryptobyte: high-tag number identifier octets not supported: 0x%x", tag)
return
}
b.AddUint8(uint8(tag))
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/net/proxy/per_host.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/net/proxy/per_host.go
index d7d4b8b6e..32bdf435e 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/net/proxy/per_host.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/net/proxy/per_host.go
@@ -7,6 +7,7 @@ package proxy
import (
"context"
"net"
+ "net/netip"
"strings"
)
@@ -57,7 +58,8 @@ func (p *PerHost) DialContext(ctx context.Context, network, addr string) (c net.
}
func (p *PerHost) dialerForRequest(host string) Dialer {
- if ip := net.ParseIP(host); ip != nil {
+ if nip, err := netip.ParseAddr(host); err == nil {
+ ip := net.IP(nip.AsSlice())
for _, net := range p.bypassNetworks {
if net.Contains(ip) {
return p.bypass
@@ -108,8 +110,8 @@ func (p *PerHost) AddFromString(s string) {
}
continue
}
- if ip := net.ParseIP(host); ip != nil {
- p.AddIP(ip)
+ if nip, err := netip.ParseAddr(host); err == nil {
+ p.AddIP(net.IP(nip.AsSlice()))
continue
}
if strings.HasPrefix(host, "*.") {
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu.go
index 9c105f23a..63541994e 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu.go
@@ -149,6 +149,18 @@ var ARM struct {
_ CacheLinePad
}
+// The booleans in Loong64 contain the correspondingly named cpu feature bit.
+// The struct is padded to avoid false sharing.
+var Loong64 struct {
+ _ CacheLinePad
+ HasLSX bool // support 128-bit vector extension
+ HasLASX bool // support 256-bit vector extension
+ HasCRC32 bool // support CRC instruction
+ HasLAM_BH bool // support AM{SWAP/ADD}[_DB].{B/H} instruction
+ HasLAMCAS bool // support AMCAS[_DB].{B/H/W/D} instruction
+ _ CacheLinePad
+}
+
// MIPS64X contains the supported CPU features of the current mips64/mips64le
// platforms. If the current platform is not mips64/mips64le or the current
// operating system is not Linux then all feature flags are false.
@@ -220,6 +232,17 @@ var RISCV64 struct {
HasZba bool // Address generation instructions extension
HasZbb bool // Basic bit-manipulation extension
HasZbs bool // Single-bit instructions extension
+ HasZvbb bool // Vector Basic Bit-manipulation
+ HasZvbc bool // Vector Carryless Multiplication
+ HasZvkb bool // Vector Cryptography Bit-manipulation
+ HasZvkt bool // Vector Data-Independent Execution Latency
+ HasZvkg bool // Vector GCM/GMAC
+ HasZvkn bool // NIST Algorithm Suite (AES/SHA256/SHA512)
+ HasZvknc bool // NIST Algorithm Suite with carryless multiply
+ HasZvkng bool // NIST Algorithm Suite with GCM
+ HasZvks bool // ShangMi Algorithm Suite
+ HasZvksc bool // ShangMi Algorithm Suite with carryless multiplication
+ HasZvksg bool // ShangMi Algorithm Suite with GCM
_ CacheLinePad
}
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go
new file mode 100644
index 000000000..4f3411432
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_loong64.go
@@ -0,0 +1,22 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cpu
+
+// HWCAP bits. These are exposed by the Linux kernel.
+const (
+ hwcap_LOONGARCH_LSX = 1 << 4
+ hwcap_LOONGARCH_LASX = 1 << 5
+)
+
+func doinit() {
+ // TODO: Features that require kernel support like LSX and LASX can
+ // be detected here once needed in std library or by the compiler.
+ Loong64.HasLSX = hwcIsSet(hwCap, hwcap_LOONGARCH_LSX)
+ Loong64.HasLASX = hwcIsSet(hwCap, hwcap_LOONGARCH_LASX)
+}
+
+func hwcIsSet(hwc uint, val uint) bool {
+ return hwc&val != 0
+}
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go
index 7d902b684..a428dec9c 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_noinit.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
+//go:build linux && !arm && !arm64 && !loong64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x && !riscv64
package cpu
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
index cb4a0c572..ad741536f 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_linux_riscv64.go
@@ -58,6 +58,15 @@ const (
riscv_HWPROBE_EXT_ZBA = 0x8
riscv_HWPROBE_EXT_ZBB = 0x10
riscv_HWPROBE_EXT_ZBS = 0x20
+ riscv_HWPROBE_EXT_ZVBB = 0x20000
+ riscv_HWPROBE_EXT_ZVBC = 0x40000
+ riscv_HWPROBE_EXT_ZVKB = 0x80000
+ riscv_HWPROBE_EXT_ZVKG = 0x100000
+ riscv_HWPROBE_EXT_ZVKNED = 0x200000
+ riscv_HWPROBE_EXT_ZVKNHB = 0x800000
+ riscv_HWPROBE_EXT_ZVKSED = 0x1000000
+ riscv_HWPROBE_EXT_ZVKSH = 0x2000000
+ riscv_HWPROBE_EXT_ZVKT = 0x4000000
riscv_HWPROBE_KEY_CPUPERF_0 = 0x5
riscv_HWPROBE_MISALIGNED_FAST = 0x3
riscv_HWPROBE_MISALIGNED_MASK = 0x7
@@ -99,6 +108,20 @@ func doinit() {
RISCV64.HasZba = isSet(v, riscv_HWPROBE_EXT_ZBA)
RISCV64.HasZbb = isSet(v, riscv_HWPROBE_EXT_ZBB)
RISCV64.HasZbs = isSet(v, riscv_HWPROBE_EXT_ZBS)
+ RISCV64.HasZvbb = isSet(v, riscv_HWPROBE_EXT_ZVBB)
+ RISCV64.HasZvbc = isSet(v, riscv_HWPROBE_EXT_ZVBC)
+ RISCV64.HasZvkb = isSet(v, riscv_HWPROBE_EXT_ZVKB)
+ RISCV64.HasZvkg = isSet(v, riscv_HWPROBE_EXT_ZVKG)
+ RISCV64.HasZvkt = isSet(v, riscv_HWPROBE_EXT_ZVKT)
+ // Cryptography shorthand extensions
+ RISCV64.HasZvkn = isSet(v, riscv_HWPROBE_EXT_ZVKNED) &&
+ isSet(v, riscv_HWPROBE_EXT_ZVKNHB) && RISCV64.HasZvkb && RISCV64.HasZvkt
+ RISCV64.HasZvknc = RISCV64.HasZvkn && RISCV64.HasZvbc
+ RISCV64.HasZvkng = RISCV64.HasZvkn && RISCV64.HasZvkg
+ RISCV64.HasZvks = isSet(v, riscv_HWPROBE_EXT_ZVKSED) &&
+ isSet(v, riscv_HWPROBE_EXT_ZVKSH) && RISCV64.HasZvkb && RISCV64.HasZvkt
+ RISCV64.HasZvksc = RISCV64.HasZvks && RISCV64.HasZvbc
+ RISCV64.HasZvksg = RISCV64.HasZvks && RISCV64.HasZvkg
}
if pairs[1].key != -1 {
v := pairs[1].value & riscv_HWPROBE_MISALIGNED_MASK
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.go
index 558635850..45ecb29ae 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.go
@@ -8,5 +8,43 @@ package cpu
const cacheLineSize = 64
+// Bit fields for CPUCFG registers, Related reference documents:
+// https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html#_cpucfg
+const (
+ // CPUCFG1 bits
+ cpucfg1_CRC32 = 1 << 25
+
+ // CPUCFG2 bits
+ cpucfg2_LAM_BH = 1 << 27
+ cpucfg2_LAMCAS = 1 << 28
+)
+
func initOptions() {
+ options = []option{
+ {Name: "lsx", Feature: &Loong64.HasLSX},
+ {Name: "lasx", Feature: &Loong64.HasLASX},
+ {Name: "crc32", Feature: &Loong64.HasCRC32},
+ {Name: "lam_bh", Feature: &Loong64.HasLAM_BH},
+ {Name: "lamcas", Feature: &Loong64.HasLAMCAS},
+ }
+
+ // The CPUCFG data on Loong64 only reflects the hardware capabilities,
+ // not the kernel support status, so features such as LSX and LASX that
+ // require kernel support cannot be obtained from the CPUCFG data.
+ //
+ // These features only require hardware capability support and do not
+ // require kernel specific support, so they can be obtained directly
+ // through CPUCFG
+ cfg1 := get_cpucfg(1)
+ cfg2 := get_cpucfg(2)
+
+ Loong64.HasCRC32 = cfgIsSet(cfg1, cpucfg1_CRC32)
+ Loong64.HasLAMCAS = cfgIsSet(cfg2, cpucfg2_LAMCAS)
+ Loong64.HasLAM_BH = cfgIsSet(cfg2, cpucfg2_LAM_BH)
+}
+
+func get_cpucfg(reg uint32) uint32
+
+func cfgIsSet(cfg uint32, val uint32) bool {
+ return cfg&val != 0
}
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.s b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.s
new file mode 100644
index 000000000..71cbaf1ce
--- /dev/null
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_loong64.s
@@ -0,0 +1,13 @@
+// Copyright 2025 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func get_cpucfg(reg uint32) uint32
+TEXT ·get_cpucfg(SB), NOSPLIT|NOFRAME, $0
+ MOVW reg+0(FP), R5
+ // CPUCFG R5, R4 = 0x00006ca4
+ WORD $0x00006ca4
+ MOVW R4, ret+8(FP)
+ RET
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_riscv64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_riscv64.go
index aca3199c9..0f617aef5 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_riscv64.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/cpu_riscv64.go
@@ -16,5 +16,17 @@ func initOptions() {
{Name: "zba", Feature: &RISCV64.HasZba},
{Name: "zbb", Feature: &RISCV64.HasZbb},
{Name: "zbs", Feature: &RISCV64.HasZbs},
+ // RISC-V Cryptography Extensions
+ {Name: "zvbb", Feature: &RISCV64.HasZvbb},
+ {Name: "zvbc", Feature: &RISCV64.HasZvbc},
+ {Name: "zvkb", Feature: &RISCV64.HasZvkb},
+ {Name: "zvkg", Feature: &RISCV64.HasZvkg},
+ {Name: "zvkt", Feature: &RISCV64.HasZvkt},
+ {Name: "zvkn", Feature: &RISCV64.HasZvkn},
+ {Name: "zvknc", Feature: &RISCV64.HasZvknc},
+ {Name: "zvkng", Feature: &RISCV64.HasZvkng},
+ {Name: "zvks", Feature: &RISCV64.HasZvks},
+ {Name: "zvksc", Feature: &RISCV64.HasZvksc},
+ {Name: "zvksg", Feature: &RISCV64.HasZvksg},
}
}
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/parse.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/parse.go
index 762b63d68..56a7e1a17 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/parse.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/cpu/parse.go
@@ -13,7 +13,7 @@ import "strconv"
// https://golang.org/cl/209597.
func parseRelease(rel string) (major, minor, patch int, ok bool) {
// Strip anything after a dash or plus.
- for i := 0; i < len(rel); i++ {
+ for i := range len(rel) {
if rel[i] == '-' || rel[i] == '+' {
rel = rel[:i]
break
@@ -21,7 +21,7 @@ func parseRelease(rel string) (major, minor, patch int, ok bool) {
}
next := func() (int, bool) {
- for i := 0; i < len(rel); i++ {
+ for i := range len(rel) {
if rel[i] == '.' {
ver, err := strconv.Atoi(rel[:i])
rel = rel[i+1:]
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_darwin.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_darwin.go
index 099867dee..798f61ad3 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_darwin.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_darwin.go
@@ -602,7 +602,150 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
return
}
-//sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
+// sys connectx(fd int, endpoints *SaEndpoints, associd SaeAssocID, flags uint32, iov []Iovec, n *uintptr, connid *SaeConnID) (err error)
+const minIovec = 8
+
+func Readv(fd int, iovs [][]byte) (n int, err error) {
+ if !darwinKernelVersionMin(11, 0, 0) {
+ return 0, ENOSYS
+ }
+
+ iovecs := make([]Iovec, 0, minIovec)
+ iovecs = appendBytes(iovecs, iovs)
+ n, err = readv(fd, iovecs)
+ readvRacedetect(iovecs, n, err)
+ return n, err
+}
+
+func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
+ if !darwinKernelVersionMin(11, 0, 0) {
+ return 0, ENOSYS
+ }
+ iovecs := make([]Iovec, 0, minIovec)
+ iovecs = appendBytes(iovecs, iovs)
+ n, err = preadv(fd, iovecs, offset)
+ readvRacedetect(iovecs, n, err)
+ return n, err
+}
+
+func Writev(fd int, iovs [][]byte) (n int, err error) {
+ if !darwinKernelVersionMin(11, 0, 0) {
+ return 0, ENOSYS
+ }
+
+ iovecs := make([]Iovec, 0, minIovec)
+ iovecs = appendBytes(iovecs, iovs)
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ n, err = writev(fd, iovecs)
+ writevRacedetect(iovecs, n)
+ return n, err
+}
+
+func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
+ if !darwinKernelVersionMin(11, 0, 0) {
+ return 0, ENOSYS
+ }
+
+ iovecs := make([]Iovec, 0, minIovec)
+ iovecs = appendBytes(iovecs, iovs)
+ if raceenabled {
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
+ }
+ n, err = pwritev(fd, iovecs, offset)
+ writevRacedetect(iovecs, n)
+ return n, err
+}
+
+func appendBytes(vecs []Iovec, bs [][]byte) []Iovec {
+ for _, b := range bs {
+ var v Iovec
+ v.SetLen(len(b))
+ if len(b) > 0 {
+ v.Base = &b[0]
+ } else {
+ v.Base = (*byte)(unsafe.Pointer(&_zero))
+ }
+ vecs = append(vecs, v)
+ }
+ return vecs
+}
+
+func writevRacedetect(iovecs []Iovec, n int) {
+ if !raceenabled {
+ return
+ }
+ for i := 0; n > 0 && i < len(iovecs); i++ {
+ m := int(iovecs[i].Len)
+ if m > n {
+ m = n
+ }
+ n -= m
+ if m > 0 {
+ raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
+ }
+ }
+}
+
+func readvRacedetect(iovecs []Iovec, n int, err error) {
+ if !raceenabled {
+ return
+ }
+ for i := 0; n > 0 && i < len(iovecs); i++ {
+ m := int(iovecs[i].Len)
+ if m > n {
+ m = n
+ }
+ n -= m
+ if m > 0 {
+ raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
+ }
+ }
+ if err == nil {
+ raceAcquire(unsafe.Pointer(&ioSync))
+ }
+}
+
+func darwinMajorMinPatch() (maj, min, patch int, err error) {
+ var un Utsname
+ err = Uname(&un)
+ if err != nil {
+ return
+ }
+
+ var mmp [3]int
+ c := 0
+Loop:
+ for _, b := range un.Release[:] {
+ switch {
+ case b >= '0' && b <= '9':
+ mmp[c] = 10*mmp[c] + int(b-'0')
+ case b == '.':
+ c++
+ if c > 2 {
+ return 0, 0, 0, ENOTSUP
+ }
+ case b == 0:
+ break Loop
+ default:
+ return 0, 0, 0, ENOTSUP
+ }
+ }
+ if c != 2 {
+ return 0, 0, 0, ENOTSUP
+ }
+ return mmp[0], mmp[1], mmp[2], nil
+}
+
+func darwinKernelVersionMin(maj, min, patch int) bool {
+ actualMaj, actualMin, actualPatch, err := darwinMajorMinPatch()
+ if err != nil {
+ return false
+ }
+ return actualMaj > maj || actualMaj == maj && (actualMin > min || actualMin == min && actualPatch >= patch)
+}
+
//sys sendfile(infd int, outfd int, offset int64, len *int64, hdtr unsafe.Pointer, flags int) (err error)
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error)
@@ -705,3 +848,7 @@ func Connectx(fd int, srcIf uint32, srcAddr, dstAddr Sockaddr, associd SaeAssocI
//sys write(fd int, p []byte) (n int, err error)
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
//sys munmap(addr uintptr, length uintptr) (err error)
+//sys readv(fd int, iovecs []Iovec) (n int, err error)
+//sys preadv(fd int, iovecs []Iovec, offset int64) (n int, err error)
+//sys writev(fd int, iovecs []Iovec) (n int, err error)
+//sys pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error)
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_linux.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_linux.go
index 230a94549..4958a6570 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_linux.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/syscall_linux.go
@@ -13,6 +13,7 @@ package unix
import (
"encoding/binary"
+ "slices"
"strconv"
"syscall"
"time"
@@ -417,7 +418,7 @@ func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
return nil, 0, EINVAL
}
sa.raw.Family = AF_UNIX
- for i := 0; i < n; i++ {
+ for i := range n {
sa.raw.Path[i] = int8(name[i])
}
// length is family (uint16), name, NUL.
@@ -507,7 +508,7 @@ func (sa *SockaddrL2) sockaddr() (unsafe.Pointer, _Socklen, error) {
psm := (*[2]byte)(unsafe.Pointer(&sa.raw.Psm))
psm[0] = byte(sa.PSM)
psm[1] = byte(sa.PSM >> 8)
- for i := 0; i < len(sa.Addr); i++ {
+ for i := range len(sa.Addr) {
sa.raw.Bdaddr[i] = sa.Addr[len(sa.Addr)-1-i]
}
cid := (*[2]byte)(unsafe.Pointer(&sa.raw.Cid))
@@ -589,11 +590,11 @@ func (sa *SockaddrCAN) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
sa.raw.Addr[i] = rx[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
sa.raw.Addr[i+4] = tx[i]
}
return unsafe.Pointer(&sa.raw), SizeofSockaddrCAN, nil
@@ -618,11 +619,11 @@ func (sa *SockaddrCANJ1939) sockaddr() (unsafe.Pointer, _Socklen, error) {
sa.raw.Family = AF_CAN
sa.raw.Ifindex = int32(sa.Ifindex)
n := (*[8]byte)(unsafe.Pointer(&sa.Name))
- for i := 0; i < 8; i++ {
+ for i := range 8 {
sa.raw.Addr[i] = n[i]
}
p := (*[4]byte)(unsafe.Pointer(&sa.PGN))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
sa.raw.Addr[i+8] = p[i]
}
sa.raw.Addr[12] = sa.Addr
@@ -911,7 +912,7 @@ func (sa *SockaddrIUCV) sockaddr() (unsafe.Pointer, _Socklen, error) {
// These are EBCDIC encoded by the kernel, but we still need to pad them
// with blanks. Initializing with blanks allows the caller to feed in either
// a padded or an unpadded string.
- for i := 0; i < 8; i++ {
+ for i := range 8 {
sa.raw.Nodeid[i] = ' '
sa.raw.User_id[i] = ' '
sa.raw.Name[i] = ' '
@@ -1148,7 +1149,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
var user [8]byte
var name [8]byte
- for i := 0; i < 8; i++ {
+ for i := range 8 {
user[i] = byte(pp.User_id[i])
name[i] = byte(pp.Name[i])
}
@@ -1173,11 +1174,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex),
}
name := (*[8]byte)(unsafe.Pointer(&sa.Name))
- for i := 0; i < 8; i++ {
+ for i := range 8 {
name[i] = pp.Addr[i]
}
pgn := (*[4]byte)(unsafe.Pointer(&sa.PGN))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
pgn[i] = pp.Addr[i+8]
}
addr := (*[1]byte)(unsafe.Pointer(&sa.Addr))
@@ -1188,11 +1189,11 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Ifindex: int(pp.Ifindex),
}
rx := (*[4]byte)(unsafe.Pointer(&sa.RxID))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
rx[i] = pp.Addr[i]
}
tx := (*[4]byte)(unsafe.Pointer(&sa.TxID))
- for i := 0; i < 4; i++ {
+ for i := range 4 {
tx[i] = pp.Addr[i+4]
}
return sa, nil
@@ -2216,10 +2217,7 @@ func readvRacedetect(iovecs []Iovec, n int, err error) {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
- m := int(iovecs[i].Len)
- if m > n {
- m = n
- }
+ m := min(int(iovecs[i].Len), n)
n -= m
if m > 0 {
raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
@@ -2270,10 +2268,7 @@ func writevRacedetect(iovecs []Iovec, n int) {
return
}
for i := 0; n > 0 && i < len(iovecs); i++ {
- m := int(iovecs[i].Len)
- if m > n {
- m = n
- }
+ m := min(int(iovecs[i].Len), n)
n -= m
if m > 0 {
raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
@@ -2320,12 +2315,7 @@ func isGroupMember(gid int) bool {
return false
}
- for _, g := range groups {
- if g == gid {
- return true
- }
- }
- return false
+ return slices.Contains(groups, gid)
}
func isCapDacOverrideSet() bool {
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
index 24b346e1a..813c05b66 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.go
@@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func readv(fd int, iovecs []Iovec) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_readv_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_preadv_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writev(fd int, iovecs []Iovec) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_writev_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pwritev_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat64_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
index ebd213100..fda328582 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_amd64.s
@@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
+TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_readv(SB)
+GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
+DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
+
+TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_preadv(SB)
+GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
+DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
+
+TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_writev(SB)
+GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
+DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
+
+TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pwritev(SB)
+GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
+
TEXT libc_fstat64_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat64(SB)
GLOBL ·libc_fstat64_trampoline_addr(SB), RODATA, $8
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
index 824b9c2d5..e6f58f3c6 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.go
@@ -2512,6 +2512,90 @@ var libc_munmap_trampoline_addr uintptr
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func readv(fd int, iovecs []Iovec) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall(libc_readv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_readv_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_readv readv "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func preadv(fd int, iovecs []Iovec, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall6(libc_preadv_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_preadv_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_preadv preadv "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func writev(fd int, iovecs []Iovec) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall(libc_writev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)))
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_writev_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_writev writev "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func pwritev(fd int, iovecs []Iovec, offset int64) (n int, err error) {
+ var _p0 unsafe.Pointer
+ if len(iovecs) > 0 {
+ _p0 = unsafe.Pointer(&iovecs[0])
+ } else {
+ _p0 = unsafe.Pointer(&_zero)
+ }
+ r0, _, e1 := syscall_syscall6(libc_pwritev_trampoline_addr, uintptr(fd), uintptr(_p0), uintptr(len(iovecs)), uintptr(offset), 0, 0)
+ n = int(r0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+var libc_pwritev_trampoline_addr uintptr
+
+//go:cgo_import_dynamic libc_pwritev pwritev "/usr/lib/libSystem.B.dylib"
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Fstat(fd int, stat *Stat_t) (err error) {
_, _, e1 := syscall_syscall(libc_fstat_trampoline_addr, uintptr(fd), uintptr(unsafe.Pointer(stat)), 0)
if e1 != 0 {
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
index 4f178a229..7f8998b90 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/unix/zsyscall_darwin_arm64.s
@@ -738,6 +738,26 @@ TEXT libc_munmap_trampoline<>(SB),NOSPLIT,$0-0
GLOBL ·libc_munmap_trampoline_addr(SB), RODATA, $8
DATA ·libc_munmap_trampoline_addr(SB)/8, $libc_munmap_trampoline<>(SB)
+TEXT libc_readv_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_readv(SB)
+GLOBL ·libc_readv_trampoline_addr(SB), RODATA, $8
+DATA ·libc_readv_trampoline_addr(SB)/8, $libc_readv_trampoline<>(SB)
+
+TEXT libc_preadv_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_preadv(SB)
+GLOBL ·libc_preadv_trampoline_addr(SB), RODATA, $8
+DATA ·libc_preadv_trampoline_addr(SB)/8, $libc_preadv_trampoline<>(SB)
+
+TEXT libc_writev_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_writev(SB)
+GLOBL ·libc_writev_trampoline_addr(SB), RODATA, $8
+DATA ·libc_writev_trampoline_addr(SB)/8, $libc_writev_trampoline<>(SB)
+
+TEXT libc_pwritev_trampoline<>(SB),NOSPLIT,$0-0
+ JMP libc_pwritev(SB)
+GLOBL ·libc_pwritev_trampoline_addr(SB), RODATA, $8
+DATA ·libc_pwritev_trampoline_addr(SB)/8, $libc_pwritev_trampoline<>(SB)
+
TEXT libc_fstat_trampoline<>(SB),NOSPLIT,$0-0
JMP libc_fstat(SB)
GLOBL ·libc_fstat_trampoline_addr(SB), RODATA, $8
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/security_windows.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/security_windows.go
index b6e1ab76f..a8b0364c7 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/security_windows.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/security_windows.go
@@ -1303,7 +1303,10 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DE
return nil, err
}
if absoluteSDSize > 0 {
- absoluteSD = (*SECURITY_DESCRIPTOR)(unsafe.Pointer(&make([]byte, absoluteSDSize)[0]))
+ absoluteSD = new(SECURITY_DESCRIPTOR)
+ if unsafe.Sizeof(*absoluteSD) < uintptr(absoluteSDSize) {
+ panic("sizeof(SECURITY_DESCRIPTOR) too small")
+ }
}
var (
dacl *ACL
@@ -1312,19 +1315,55 @@ func (selfRelativeSD *SECURITY_DESCRIPTOR) ToAbsolute() (absoluteSD *SECURITY_DE
group *SID
)
if daclSize > 0 {
- dacl = (*ACL)(unsafe.Pointer(&make([]byte, daclSize)[0]))
+ dacl = (*ACL)(unsafe.Pointer(unsafe.SliceData(make([]byte, daclSize))))
}
if saclSize > 0 {
- sacl = (*ACL)(unsafe.Pointer(&make([]byte, saclSize)[0]))
+ sacl = (*ACL)(unsafe.Pointer(unsafe.SliceData(make([]byte, saclSize))))
}
if ownerSize > 0 {
- owner = (*SID)(unsafe.Pointer(&make([]byte, ownerSize)[0]))
+ owner = (*SID)(unsafe.Pointer(unsafe.SliceData(make([]byte, ownerSize))))
}
if groupSize > 0 {
- group = (*SID)(unsafe.Pointer(&make([]byte, groupSize)[0]))
+ group = (*SID)(unsafe.Pointer(unsafe.SliceData(make([]byte, groupSize))))
}
+ // We call into Windows via makeAbsoluteSD, which sets up
+ // pointers within absoluteSD that point to other chunks of memory
+ // we pass into makeAbsoluteSD, and that happens outside the view of the GC.
+ // We therefore take some care here to then verify the pointers are as we expect
+ // and set them explicitly in view of the GC. See https://go.dev/issue/73199.
+ // TODO: consider weak pointers once Go 1.24 is appropriate. See suggestion in https://go.dev/cl/663575.
err = makeAbsoluteSD(selfRelativeSD, absoluteSD, &absoluteSDSize,
dacl, &daclSize, sacl, &saclSize, owner, &ownerSize, group, &groupSize)
+ if err != nil {
+ // Don't return absoluteSD, which might be partially initialized.
+ return nil, err
+ }
+ // Before using any fields, verify absoluteSD is in the format we expect according to Windows.
+ // See https://learn.microsoft.com/en-us/windows/win32/secauthz/absolute-and-self-relative-security-descriptors
+ absControl, _, err := absoluteSD.Control()
+ if err != nil {
+ panic("absoluteSD: " + err.Error())
+ }
+ if absControl&SE_SELF_RELATIVE != 0 {
+ panic("absoluteSD not in absolute format")
+ }
+ if absoluteSD.dacl != dacl {
+ panic("dacl pointer mismatch")
+ }
+ if absoluteSD.sacl != sacl {
+ panic("sacl pointer mismatch")
+ }
+ if absoluteSD.owner != owner {
+ panic("owner pointer mismatch")
+ }
+ if absoluteSD.group != group {
+ panic("group pointer mismatch")
+ }
+ absoluteSD.dacl = dacl
+ absoluteSD.sacl = sacl
+ absoluteSD.owner = owner
+ absoluteSD.group = group
+
return
}
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/syscall_windows.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/syscall_windows.go
index 4a3254386..640f6b153 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/syscall_windows.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/syscall_windows.go
@@ -870,6 +870,7 @@ const socket_error = uintptr(^uint32(0))
//sys WSARecvFrom(s Handle, bufs *WSABuf, bufcnt uint32, recvd *uint32, flags *uint32, from *RawSockaddrAny, fromlen *int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSARecvFrom
//sys WSASendTo(s Handle, bufs *WSABuf, bufcnt uint32, sent *uint32, flags uint32, to *RawSockaddrAny, tolen int32, overlapped *Overlapped, croutine *byte) (err error) [failretval==socket_error] = ws2_32.WSASendTo
//sys WSASocket(af int32, typ int32, protocol int32, protoInfo *WSAProtocolInfo, group uint32, flags uint32) (handle Handle, err error) [failretval==InvalidHandle] = ws2_32.WSASocketW
+//sys WSADuplicateSocket(s Handle, processID uint32, info *WSAProtocolInfo) (err error) [failretval!=0] = ws2_32.WSADuplicateSocketW
//sys GetHostByName(name string) (h *Hostent, err error) [failretval==nil] = ws2_32.gethostbyname
//sys GetServByName(name string, proto string) (s *Servent, err error) [failretval==nil] = ws2_32.getservbyname
//sys Ntohs(netshort uint16) (u uint16) = ws2_32.ntohs
@@ -1698,8 +1699,9 @@ func NewNTUnicodeString(s string) (*NTUnicodeString, error) {
// Slice returns a uint16 slice that aliases the data in the NTUnicodeString.
func (s *NTUnicodeString) Slice() []uint16 {
- slice := unsafe.Slice(s.Buffer, s.MaximumLength)
- return slice[:s.Length]
+ // Note: this rounds the length down, if it happens
+ // to (incorrectly) be odd. Probably safer than rounding up.
+ return unsafe.Slice(s.Buffer, s.MaximumLength/2)[:s.Length/2]
}
func (s *NTUnicodeString) String() string {
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/types_windows.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/types_windows.go
index 9d138de5f..958bcf47a 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/types_windows.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/types_windows.go
@@ -1074,6 +1074,7 @@ const (
IP_ADD_MEMBERSHIP = 0xc
IP_DROP_MEMBERSHIP = 0xd
IP_PKTINFO = 0x13
+ IP_MTU_DISCOVER = 0x47
IPV6_V6ONLY = 0x1b
IPV6_UNICAST_HOPS = 0x4
@@ -1083,6 +1084,7 @@ const (
IPV6_JOIN_GROUP = 0xc
IPV6_LEAVE_GROUP = 0xd
IPV6_PKTINFO = 0x13
+ IPV6_MTU_DISCOVER = 0x47
MSG_OOB = 0x1
MSG_PEEK = 0x2
@@ -1132,6 +1134,15 @@ const (
WSASYS_STATUS_LEN = 128
)
+// enum PMTUD_STATE from ws2ipdef.h
+const (
+ IP_PMTUDISC_NOT_SET = 0
+ IP_PMTUDISC_DO = 1
+ IP_PMTUDISC_DONT = 2
+ IP_PMTUDISC_PROBE = 3
+ IP_PMTUDISC_MAX = 4
+)
+
type WSABuf struct {
Len uint32
Buf *byte
@@ -1146,6 +1157,22 @@ type WSAMsg struct {
Flags uint32
}
+type WSACMSGHDR struct {
+ Len uintptr
+ Level int32
+ Type int32
+}
+
+type IN_PKTINFO struct {
+ Addr [4]byte
+ Ifindex uint32
+}
+
+type IN6_PKTINFO struct {
+ Addr [16]byte
+ Ifindex uint32
+}
+
// Flags for WSASocket
const (
WSA_FLAG_OVERLAPPED = 0x01
@@ -2673,6 +2700,8 @@ type CommTimeouts struct {
// NTUnicodeString is a UTF-16 string for NT native APIs, corresponding to UNICODE_STRING.
type NTUnicodeString struct {
+ // Note: Length and MaximumLength are in *bytes*, not uint16s.
+ // They should always be even.
Length uint16
MaximumLength uint16
Buffer *uint16
@@ -3601,3 +3630,213 @@ const (
KLF_NOTELLSHELL = 0x00000080
KLF_SETFORPROCESS = 0x00000100
)
+
+// Virtual Key codes
+// https://docs.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
+const (
+ VK_LBUTTON = 0x01
+ VK_RBUTTON = 0x02
+ VK_CANCEL = 0x03
+ VK_MBUTTON = 0x04
+ VK_XBUTTON1 = 0x05
+ VK_XBUTTON2 = 0x06
+ VK_BACK = 0x08
+ VK_TAB = 0x09
+ VK_CLEAR = 0x0C
+ VK_RETURN = 0x0D
+ VK_SHIFT = 0x10
+ VK_CONTROL = 0x11
+ VK_MENU = 0x12
+ VK_PAUSE = 0x13
+ VK_CAPITAL = 0x14
+ VK_KANA = 0x15
+ VK_HANGEUL = 0x15
+ VK_HANGUL = 0x15
+ VK_IME_ON = 0x16
+ VK_JUNJA = 0x17
+ VK_FINAL = 0x18
+ VK_HANJA = 0x19
+ VK_KANJI = 0x19
+ VK_IME_OFF = 0x1A
+ VK_ESCAPE = 0x1B
+ VK_CONVERT = 0x1C
+ VK_NONCONVERT = 0x1D
+ VK_ACCEPT = 0x1E
+ VK_MODECHANGE = 0x1F
+ VK_SPACE = 0x20
+ VK_PRIOR = 0x21
+ VK_NEXT = 0x22
+ VK_END = 0x23
+ VK_HOME = 0x24
+ VK_LEFT = 0x25
+ VK_UP = 0x26
+ VK_RIGHT = 0x27
+ VK_DOWN = 0x28
+ VK_SELECT = 0x29
+ VK_PRINT = 0x2A
+ VK_EXECUTE = 0x2B
+ VK_SNAPSHOT = 0x2C
+ VK_INSERT = 0x2D
+ VK_DELETE = 0x2E
+ VK_HELP = 0x2F
+ VK_LWIN = 0x5B
+ VK_RWIN = 0x5C
+ VK_APPS = 0x5D
+ VK_SLEEP = 0x5F
+ VK_NUMPAD0 = 0x60
+ VK_NUMPAD1 = 0x61
+ VK_NUMPAD2 = 0x62
+ VK_NUMPAD3 = 0x63
+ VK_NUMPAD4 = 0x64
+ VK_NUMPAD5 = 0x65
+ VK_NUMPAD6 = 0x66
+ VK_NUMPAD7 = 0x67
+ VK_NUMPAD8 = 0x68
+ VK_NUMPAD9 = 0x69
+ VK_MULTIPLY = 0x6A
+ VK_ADD = 0x6B
+ VK_SEPARATOR = 0x6C
+ VK_SUBTRACT = 0x6D
+ VK_DECIMAL = 0x6E
+ VK_DIVIDE = 0x6F
+ VK_F1 = 0x70
+ VK_F2 = 0x71
+ VK_F3 = 0x72
+ VK_F4 = 0x73
+ VK_F5 = 0x74
+ VK_F6 = 0x75
+ VK_F7 = 0x76
+ VK_F8 = 0x77
+ VK_F9 = 0x78
+ VK_F10 = 0x79
+ VK_F11 = 0x7A
+ VK_F12 = 0x7B
+ VK_F13 = 0x7C
+ VK_F14 = 0x7D
+ VK_F15 = 0x7E
+ VK_F16 = 0x7F
+ VK_F17 = 0x80
+ VK_F18 = 0x81
+ VK_F19 = 0x82
+ VK_F20 = 0x83
+ VK_F21 = 0x84
+ VK_F22 = 0x85
+ VK_F23 = 0x86
+ VK_F24 = 0x87
+ VK_NUMLOCK = 0x90
+ VK_SCROLL = 0x91
+ VK_OEM_NEC_EQUAL = 0x92
+ VK_OEM_FJ_JISHO = 0x92
+ VK_OEM_FJ_MASSHOU = 0x93
+ VK_OEM_FJ_TOUROKU = 0x94
+ VK_OEM_FJ_LOYA = 0x95
+ VK_OEM_FJ_ROYA = 0x96
+ VK_LSHIFT = 0xA0
+ VK_RSHIFT = 0xA1
+ VK_LCONTROL = 0xA2
+ VK_RCONTROL = 0xA3
+ VK_LMENU = 0xA4
+ VK_RMENU = 0xA5
+ VK_BROWSER_BACK = 0xA6
+ VK_BROWSER_FORWARD = 0xA7
+ VK_BROWSER_REFRESH = 0xA8
+ VK_BROWSER_STOP = 0xA9
+ VK_BROWSER_SEARCH = 0xAA
+ VK_BROWSER_FAVORITES = 0xAB
+ VK_BROWSER_HOME = 0xAC
+ VK_VOLUME_MUTE = 0xAD
+ VK_VOLUME_DOWN = 0xAE
+ VK_VOLUME_UP = 0xAF
+ VK_MEDIA_NEXT_TRACK = 0xB0
+ VK_MEDIA_PREV_TRACK = 0xB1
+ VK_MEDIA_STOP = 0xB2
+ VK_MEDIA_PLAY_PAUSE = 0xB3
+ VK_LAUNCH_MAIL = 0xB4
+ VK_LAUNCH_MEDIA_SELECT = 0xB5
+ VK_LAUNCH_APP1 = 0xB6
+ VK_LAUNCH_APP2 = 0xB7
+ VK_OEM_1 = 0xBA
+ VK_OEM_PLUS = 0xBB
+ VK_OEM_COMMA = 0xBC
+ VK_OEM_MINUS = 0xBD
+ VK_OEM_PERIOD = 0xBE
+ VK_OEM_2 = 0xBF
+ VK_OEM_3 = 0xC0
+ VK_OEM_4 = 0xDB
+ VK_OEM_5 = 0xDC
+ VK_OEM_6 = 0xDD
+ VK_OEM_7 = 0xDE
+ VK_OEM_8 = 0xDF
+ VK_OEM_AX = 0xE1
+ VK_OEM_102 = 0xE2
+ VK_ICO_HELP = 0xE3
+ VK_ICO_00 = 0xE4
+ VK_PROCESSKEY = 0xE5
+ VK_ICO_CLEAR = 0xE6
+ VK_OEM_RESET = 0xE9
+ VK_OEM_JUMP = 0xEA
+ VK_OEM_PA1 = 0xEB
+ VK_OEM_PA2 = 0xEC
+ VK_OEM_PA3 = 0xED
+ VK_OEM_WSCTRL = 0xEE
+ VK_OEM_CUSEL = 0xEF
+ VK_OEM_ATTN = 0xF0
+ VK_OEM_FINISH = 0xF1
+ VK_OEM_COPY = 0xF2
+ VK_OEM_AUTO = 0xF3
+ VK_OEM_ENLW = 0xF4
+ VK_OEM_BACKTAB = 0xF5
+ VK_ATTN = 0xF6
+ VK_CRSEL = 0xF7
+ VK_EXSEL = 0xF8
+ VK_EREOF = 0xF9
+ VK_PLAY = 0xFA
+ VK_ZOOM = 0xFB
+ VK_NONAME = 0xFC
+ VK_PA1 = 0xFD
+ VK_OEM_CLEAR = 0xFE
+)
+
+// Mouse button constants.
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str
+const (
+ FROM_LEFT_1ST_BUTTON_PRESSED = 0x0001
+ RIGHTMOST_BUTTON_PRESSED = 0x0002
+ FROM_LEFT_2ND_BUTTON_PRESSED = 0x0004
+ FROM_LEFT_3RD_BUTTON_PRESSED = 0x0008
+ FROM_LEFT_4TH_BUTTON_PRESSED = 0x0010
+)
+
+// Control key state constaints.
+// https://docs.microsoft.com/en-us/windows/console/key-event-record-str
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str
+const (
+ CAPSLOCK_ON = 0x0080
+ ENHANCED_KEY = 0x0100
+ LEFT_ALT_PRESSED = 0x0002
+ LEFT_CTRL_PRESSED = 0x0008
+ NUMLOCK_ON = 0x0020
+ RIGHT_ALT_PRESSED = 0x0001
+ RIGHT_CTRL_PRESSED = 0x0004
+ SCROLLLOCK_ON = 0x0040
+ SHIFT_PRESSED = 0x0010
+)
+
+// Mouse event record event flags.
+// https://docs.microsoft.com/en-us/windows/console/mouse-event-record-str
+const (
+ MOUSE_MOVED = 0x0001
+ DOUBLE_CLICK = 0x0002
+ MOUSE_WHEELED = 0x0004
+ MOUSE_HWHEELED = 0x0008
+)
+
+// Input Record Event Types
+// https://learn.microsoft.com/en-us/windows/console/input-record-str
+const (
+ FOCUS_EVENT = 0x0010
+ KEY_EVENT = 0x0001
+ MENU_EVENT = 0x0008
+ MOUSE_EVENT = 0x0002
+ WINDOW_BUFFER_SIZE_EVENT = 0x0004
+)
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/zsyscall_windows.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/zsyscall_windows.go
index 01c0716c2..a58bc48b8 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/zsyscall_windows.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/sys/windows/zsyscall_windows.go
@@ -511,6 +511,7 @@ var (
procFreeAddrInfoW = modws2_32.NewProc("FreeAddrInfoW")
procGetAddrInfoW = modws2_32.NewProc("GetAddrInfoW")
procWSACleanup = modws2_32.NewProc("WSACleanup")
+ procWSADuplicateSocketW = modws2_32.NewProc("WSADuplicateSocketW")
procWSAEnumProtocolsW = modws2_32.NewProc("WSAEnumProtocolsW")
procWSAGetOverlappedResult = modws2_32.NewProc("WSAGetOverlappedResult")
procWSAIoctl = modws2_32.NewProc("WSAIoctl")
@@ -4391,6 +4392,14 @@ func WSACleanup() (err error) {
return
}
+func WSADuplicateSocket(s Handle, processID uint32, info *WSAProtocolInfo) (err error) {
+ r1, _, e1 := syscall.Syscall(procWSADuplicateSocketW.Addr(), 3, uintptr(s), uintptr(processID), uintptr(unsafe.Pointer(info)))
+ if r1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
func WSAEnumProtocols(protocols *int32, protocolBuffer *WSAProtocolInfo, bufferLength *uint32) (n int32, err error) {
r0, _, e1 := syscall.Syscall(procWSAEnumProtocolsW.Addr(), 3, uintptr(unsafe.Pointer(protocols)), uintptr(unsafe.Pointer(protocolBuffer)), uintptr(unsafe.Pointer(bufferLength)))
n = int32(r0)
diff --git a/trunk/3rdparty/srs-bench/vendor/golang.org/x/term/terminal.go b/trunk/3rdparty/srs-bench/vendor/golang.org/x/term/terminal.go
index f636667fb..13e9a64ad 100644
--- a/trunk/3rdparty/srs-bench/vendor/golang.org/x/term/terminal.go
+++ b/trunk/3rdparty/srs-bench/vendor/golang.org/x/term/terminal.go
@@ -6,6 +6,7 @@ package term
import (
"bytes"
+ "fmt"
"io"
"runtime"
"strconv"
@@ -36,6 +37,26 @@ var vt100EscapeCodes = EscapeCodes{
Reset: []byte{keyEscape, '[', '0', 'm'},
}
+// A History provides a (possibly bounded) queue of input lines read by [Terminal.ReadLine].
+type History interface {
+ // Add will be called by [Terminal.ReadLine] to add
+ // a new, most recent entry to the history.
+ // It is allowed to drop any entry, including
+ // the entry being added (e.g., if it's deemed an invalid entry),
+ // the least-recent entry (e.g., to keep the history bounded),
+ // or any other entry.
+ Add(entry string)
+
+ // Len returns the number of entries in the history.
+ Len() int
+
+ // At returns an entry from the history.
+ // Index 0 is the most-recently added entry and
+ // index Len()-1 is the least-recently added entry.
+ // If index is < 0 or >= Len(), it panics.
+ At(idx int) string
+}
+
// Terminal contains the state for running a VT100 terminal that is capable of
// reading lines of input.
type Terminal struct {
@@ -44,6 +65,8 @@ type Terminal struct {
// bytes, as an index into |line|). If it returns ok=false, the key
// press is processed normally. Otherwise it returns a replacement line
// and the new cursor position.
+ //
+ // This will be disabled during ReadPassword.
AutoCompleteCallback func(line string, pos int, key rune) (newLine string, newPos int, ok bool)
// Escape contains a pointer to the escape codes for this terminal.
@@ -84,9 +107,14 @@ type Terminal struct {
remainder []byte
inBuf [256]byte
- // history contains previously entered commands so that they can be
- // accessed with the up and down keys.
- history stRingBuffer
+ // History records and retrieves lines of input read by [ReadLine] which
+ // a user can retrieve and navigate using the up and down arrow keys.
+ //
+ // It is not safe to call ReadLine concurrently with any methods on History.
+ //
+ // [NewTerminal] sets this to a default implementation that records the
+ // last 100 lines of input.
+ History History
// historyIndex stores the currently accessed history entry, where zero
// means the immediately previous entry.
historyIndex int
@@ -109,6 +137,7 @@ func NewTerminal(c io.ReadWriter, prompt string) *Terminal {
termHeight: 24,
echo: true,
historyIndex: -1,
+ History: &stRingBuffer{},
}
}
@@ -448,6 +477,23 @@ func visualLength(runes []rune) int {
return length
}
+// histroryAt unlocks the terminal and relocks it while calling History.At.
+func (t *Terminal) historyAt(idx int) (string, bool) {
+ t.lock.Unlock() // Unlock to avoid deadlock if History methods use the output writer.
+ defer t.lock.Lock() // panic in At (or Len) protection.
+ if idx < 0 || idx >= t.History.Len() {
+ return "", false
+ }
+ return t.History.At(idx), true
+}
+
+// historyAdd unlocks the terminal and relocks it while calling History.Add.
+func (t *Terminal) historyAdd(entry string) {
+ t.lock.Unlock() // Unlock to avoid deadlock if History methods use the output writer.
+ defer t.lock.Lock() // panic in Add protection.
+ t.History.Add(entry)
+}
+
// handleKey processes the given key and, optionally, returns a line of text
// that the user has entered.
func (t *Terminal) handleKey(key rune) (line string, ok bool) {
@@ -495,7 +541,7 @@ func (t *Terminal) handleKey(key rune) (line string, ok bool) {
t.pos = len(t.line)
t.moveCursorToPos(t.pos)
case keyUp:
- entry, ok := t.history.NthPreviousEntry(t.historyIndex + 1)
+ entry, ok := t.historyAt(t.historyIndex + 1)
if !ok {
return "", false
}
@@ -514,7 +560,7 @@ func (t *Terminal) handleKey(key rune) (line string, ok bool) {
t.setLine(runes, len(runes))
t.historyIndex--
default:
- entry, ok := t.history.NthPreviousEntry(t.historyIndex - 1)
+ entry, ok := t.historyAt(t.historyIndex - 1)
if ok {
t.historyIndex--
runes := []rune(entry)
@@ -692,6 +738,8 @@ func (t *Terminal) Write(buf []byte) (n int, err error) {
// ReadPassword temporarily changes the prompt and reads a password, without
// echo, from the terminal.
+//
+// The AutoCompleteCallback is disabled during this call.
func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
t.lock.Lock()
defer t.lock.Unlock()
@@ -699,6 +747,11 @@ func (t *Terminal) ReadPassword(prompt string) (line string, err error) {
oldPrompt := t.prompt
t.prompt = []rune(prompt)
t.echo = false
+ oldAutoCompleteCallback := t.AutoCompleteCallback
+ t.AutoCompleteCallback = nil
+ defer func() {
+ t.AutoCompleteCallback = oldAutoCompleteCallback
+ }()
line, err = t.readLine()
@@ -772,7 +825,7 @@ func (t *Terminal) readLine() (line string, err error) {
if lineOk {
if t.echo {
t.historyIndex = -1
- t.history.Add(line)
+ t.historyAdd(line)
}
if lineIsPasted {
err = ErrPasteIndicator
@@ -929,19 +982,23 @@ func (s *stRingBuffer) Add(a string) {
}
}
-// NthPreviousEntry returns the value passed to the nth previous call to Add.
+func (s *stRingBuffer) Len() int {
+ return s.size
+}
+
+// At returns the value passed to the nth previous call to Add.
// If n is zero then the immediately prior value is returned, if one, then the
// next most recent, and so on. If such an element doesn't exist then ok is
// false.
-func (s *stRingBuffer) NthPreviousEntry(n int) (value string, ok bool) {
+func (s *stRingBuffer) At(n int) string {
if n < 0 || n >= s.size {
- return "", false
+ panic(fmt.Sprintf("term: history index [%d] out of range [0,%d)", n, s.size))
}
index := s.head - n
if index < 0 {
index += s.max
}
- return s.entries[index], true
+ return s.entries[index]
}
// readPasswordLine reads from reader until it finds \n or io.EOF.
diff --git a/trunk/3rdparty/srs-bench/vendor/modules.txt b/trunk/3rdparty/srs-bench/vendor/modules.txt
index a04d82823..2c6673217 100644
--- a/trunk/3rdparty/srs-bench/vendor/modules.txt
+++ b/trunk/3rdparty/srs-bench/vendor/modules.txt
@@ -89,16 +89,19 @@ github.com/pion/ice/v4/internal/atomic
github.com/pion/ice/v4/internal/fakenet
github.com/pion/ice/v4/internal/stun
github.com/pion/ice/v4/internal/taskloop
-# github.com/pion/interceptor v0.1.37
+# github.com/pion/interceptor v0.1.40
## explicit; go 1.20
github.com/pion/interceptor
github.com/pion/interceptor/internal/ntp
+github.com/pion/interceptor/internal/rtpbuffer
github.com/pion/interceptor/internal/sequencenumber
+github.com/pion/interceptor/pkg/flexfec
+github.com/pion/interceptor/pkg/flexfec/util
github.com/pion/interceptor/pkg/nack
github.com/pion/interceptor/pkg/report
github.com/pion/interceptor/pkg/rfc8888
github.com/pion/interceptor/pkg/twcc
-# github.com/pion/logging v0.2.3
+# github.com/pion/logging v0.2.4
## explicit; go 1.20
github.com/pion/logging
# github.com/pion/mdns/v2 v2.0.7
@@ -110,7 +113,7 @@ github.com/pion/randutil
# github.com/pion/rtcp v1.2.15
## explicit; go 1.20
github.com/pion/rtcp
-# github.com/pion/rtp v1.8.15
+# github.com/pion/rtp v1.8.20
## explicit; go 1.20
github.com/pion/rtp
github.com/pion/rtp/codecs
@@ -119,10 +122,10 @@ github.com/pion/rtp/codecs/vp9
# github.com/pion/sctp v1.8.39
## explicit; go 1.20
github.com/pion/sctp
-# github.com/pion/sdp/v3 v3.0.11
+# github.com/pion/sdp/v3 v3.0.14
## explicit; go 1.20
github.com/pion/sdp/v3
-# github.com/pion/srtp/v3 v3.0.4
+# github.com/pion/srtp/v3 v3.0.6
## explicit; go 1.20
github.com/pion/srtp/v3
# github.com/pion/stun/v3 v3.0.0
@@ -139,15 +142,15 @@ github.com/pion/transport/v3/replaydetector
github.com/pion/transport/v3/stdnet
github.com/pion/transport/v3/utils/xor
github.com/pion/transport/v3/vnet
-# github.com/pion/turn/v4 v4.0.0
-## explicit; go 1.19
+# github.com/pion/turn/v4 v4.0.2
+## explicit; go 1.20
github.com/pion/turn/v4
github.com/pion/turn/v4/internal/allocation
github.com/pion/turn/v4/internal/client
github.com/pion/turn/v4/internal/ipnet
github.com/pion/turn/v4/internal/proto
github.com/pion/turn/v4/internal/server
-# github.com/pion/webrtc/v4 v4.1.1
+# github.com/pion/webrtc/v4 v4.1.3
## explicit; go 1.20
github.com/pion/webrtc/v4
github.com/pion/webrtc/v4/internal/fmtp
@@ -156,6 +159,7 @@ github.com/pion/webrtc/v4/internal/util
github.com/pion/webrtc/v4/pkg/media
github.com/pion/webrtc/v4/pkg/media/h264reader
github.com/pion/webrtc/v4/pkg/media/h264writer
+github.com/pion/webrtc/v4/pkg/media/h265reader
github.com/pion/webrtc/v4/pkg/media/ivfwriter
github.com/pion/webrtc/v4/pkg/media/oggreader
github.com/pion/webrtc/v4/pkg/media/oggwriter
@@ -184,14 +188,14 @@ github.com/yapingcat/gomedia/codec
# github.com/yapingcat/gomedia/mpeg2 v0.0.0-20220617074658-94762898dc25
## explicit; go 1.16
github.com/yapingcat/gomedia/mpeg2
-# golang.org/x/crypto v0.33.0
-## explicit; go 1.20
+# golang.org/x/crypto v0.39.0
+## explicit; go 1.23.0
golang.org/x/crypto/cryptobyte
golang.org/x/crypto/cryptobyte/asn1
golang.org/x/crypto/curve25519
golang.org/x/crypto/ssh/terminal
-# golang.org/x/net v0.35.0
-## explicit; go 1.18
+# golang.org/x/net v0.41.0
+## explicit; go 1.23.0
golang.org/x/net/bpf
golang.org/x/net/dns/dnsmessage
golang.org/x/net/internal/iana
@@ -200,12 +204,12 @@ golang.org/x/net/internal/socks
golang.org/x/net/ipv4
golang.org/x/net/ipv6
golang.org/x/net/proxy
-# golang.org/x/sys v0.30.0
-## explicit; go 1.18
+# golang.org/x/sys v0.33.0
+## explicit; go 1.23.0
golang.org/x/sys/cpu
golang.org/x/sys/plan9
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/term v0.29.0
-## explicit; go 1.18
+# golang.org/x/term v0.32.0
+## explicit; go 1.23.0
golang.org/x/term
diff --git a/trunk/Dockerfile.builds b/trunk/Dockerfile.builds
index 4a9f89a0e..692db26ef 100644
--- a/trunk/Dockerfile.builds
+++ b/trunk/Dockerfile.builds
@@ -26,7 +26,7 @@ RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
FROM ossrs/srs:ubuntu16-cache AS ubuntu16-all
COPY . /srs
-RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --h265=on && make
+RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
########################################################
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-baseline
@@ -35,7 +35,7 @@ RUN cd /srs/trunk && ./configure --srt=off --gb28181=off && make
FROM ossrs/srs:ubuntu18-cache AS ubuntu18-all
COPY . /srs
-RUN cd /srs/trunk && ./configure --srt=on --gb28181=on --h265=on && make
+RUN cd /srs/trunk && ./configure --srt=on --gb28181=on && make
########################################################
FROM ossrs/srs:ubuntu20-cache AS ubuntu20-baseline
diff --git a/trunk/Dockerfile.test b/trunk/Dockerfile.test
index aae3f0918..cd7bde7c5 100644
--- a/trunk/Dockerfile.test
+++ b/trunk/Dockerfile.test
@@ -18,7 +18,7 @@ WORKDIR /srs/trunk
# Note that we must enable the gcc7 or link failed.
# Please note that we must disable the ffmpeg-opus, as it negatively impacts performance. We may consider
# enabling it in the future when support for multi-threading transcoding is available.
-RUN ./configure --srt=on --gb28181=on --srt=on --apm=on --h265=on --utest=on --ffmpeg-opus=off --build-cache=on
+RUN ./configure --srt=on --gb28181=on --srt=on --apm=on --utest=on --ffmpeg-opus=off --build-cache=on
RUN make utest ${MAKEARGS}
# Build benchmark tool.
diff --git a/trunk/auto/auto_headers.sh b/trunk/auto/auto_headers.sh
index 5a85fd2a2..f15bbb8b2 100755
--- a/trunk/auto/auto_headers.sh
+++ b/trunk/auto/auto_headers.sh
@@ -92,11 +92,8 @@ else
srs_undefine_macro "SRS_FFMPEG_OPUS" $SRS_AUTO_HEADERS_H
fi
-if [[ $SRS_H265 == YES ]]; then
- srs_define_macro "SRS_H265" $SRS_AUTO_HEADERS_H
-else
- srs_undefine_macro "SRS_H265" $SRS_AUTO_HEADERS_H
-fi
+# H.265/HEVC support is always enabled
+srs_define_macro "SRS_H265" $SRS_AUTO_HEADERS_H
if [[ $SRS_SIMULATOR == YES ]]; then
srs_define_macro "SRS_SIMULATOR" $SRS_AUTO_HEADERS_H
diff --git a/trunk/auto/options.sh b/trunk/auto/options.sh
index 9a186f462..1b36046cd 100755
--- a/trunk/auto/options.sh
+++ b/trunk/auto/options.sh
@@ -6,7 +6,8 @@ help=no
SRS_HDS=NO
SRS_SRT=YES
SRS_RTC=YES
-SRS_H265=YES
+# SRS_H265 is always enabled, no longer configurable
+SRS_H265=RESERVED
SRS_GB28181=NO
SRS_CXX11=YES
SRS_CXX14=NO
@@ -189,7 +190,7 @@ Features:
--ffmpeg-fit=on|off Whether enable the FFmpeg fit(source code). Default: $(value2switch $SRS_FFMPEG_FIT)
--ffmpeg-opus=on|off Whether enable the FFmpeg native opus codec. Default: $(value2switch $SRS_FFMPEG_OPUS)
--apm=on|off Whether enable cloud logging and APM(Application Performance Monitor). Default: $(value2switch $SRS_APM)
- --h265=on|off Whether build the HEVC(H.265) support. Default: $(value2switch $SRS_H265)
+ --h265=on Whether build the HEVC(H.265) support. Always enabled.
--prefix= The absolute installation path. Default: $SRS_PREFIX
--jobs[=N] Allow N jobs at once; infinite jobs with no arg. Default: $SRS_JOBS
@@ -601,6 +602,12 @@ function apply_auto_options() {
if [[ ! -z SRS_JOBS ]]; then
export SRS_JOBS="--jobs=${SRS_JOBS}"
fi
+
+ # H.265/HEVC is always enabled, see https://github.com/ossrs/srs/issues/4349
+ if [[ $SRS_H265 != RESERVED ]]; then
+ echo "Warning: --h265 option is deprecated. H.265/HEVC support is always enabled."
+ SRS_H265=ON
+ fi
}
apply_auto_options
@@ -654,7 +661,7 @@ function regenerate_options() {
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --srt=$(value2switch $SRS_SRT)"
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --sys-srt=$(value2switch $SRS_USE_SYS_SRT)"
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --rtc=$(value2switch $SRS_RTC)"
- SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --h265=$(value2switch $SRS_H265)"
+
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --gb28181=$(value2switch $SRS_GB28181)"
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --simulator=$(value2switch $SRS_SIMULATOR)"
SRS_AUTO_CONFIGURE="${SRS_AUTO_CONFIGURE} --cxx11=$(value2switch $SRS_CXX11)"
diff --git a/trunk/configure b/trunk/configure
index 0a2e5cc26..7e59afbcd 100755
--- a/trunk/configure
+++ b/trunk/configure
@@ -736,11 +736,7 @@ if [[ $SRS_GB28181 == YES ]]; then
else
echo -e "${GREEN}Warning: GB28181 is disabled.${BLACK}"
fi
-if [[ $SRS_H265 == YES ]]; then
- echo -e "${YELLOW}Experiment: HEVC/H.265 is enabled. https://github.com/ossrs/srs/issues/465${BLACK}"
-else
- echo -e "${GREEN}Warning: HEVC/H.265 is disabled.${BLACK}"
-fi
+echo -e "${GREEN}Experiment: HEVC/H.265 is enabled. https://github.com/ossrs/srs/issues/465${BLACK}"
if [[ $SRS_SRT == YES ]]; then
echo -e "${YELLOW}Experiment: SRT is enabled. https://github.com/ossrs/srs/issues/1147${BLACK}"
else
diff --git a/trunk/doc/CHANGELOG.md b/trunk/doc/CHANGELOG.md
index 7f8364966..01144bb74 100644
--- a/trunk/doc/CHANGELOG.md
+++ b/trunk/doc/CHANGELOG.md
@@ -7,6 +7,7 @@ The changelog for SRS.
## SRS 7.0 Changelog
+* v7.0, 2025-07-04, Merge [#4412](https://github.com/ossrs/srs/pull/4412): Refine code and add tests for #4289. v7.0.45 (#4412)
* v7.0, 2025-07-04, Merge [#4413](https://github.com/ossrs/srs/pull/4413): RTMP2RTC: Support dual video track for bridge. v7.0.44 (#4413)
* v7.0, 2025-07-03, Merge [#4349](https://github.com/ossrs/srs/pull/4349): rtc2rtmp: Support WebRTC-to-RTMP conversion with HEVC. v7.0.43 (#4349)
* v7.0, 2025-06-04, Merge [#4310](https://github.com/ossrs/srs/pull/4310): Player: Get codec by webrtc api: pc.getStats. v7.0.42 (#4310)
diff --git a/trunk/src/app/srs_app_dvr.cpp b/trunk/src/app/srs_app_dvr.cpp
index 640445fcc..4b46d303f 100644
--- a/trunk/src/app/srs_app_dvr.cpp
+++ b/trunk/src/app/srs_app_dvr.cpp
@@ -870,9 +870,7 @@ srs_error_t SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
int size = msg->size;
bool codec_ok = SrsFlvVideo::h264(payload, size);
-#ifdef SRS_H265
codec_ok = codec_ok? true : SrsFlvVideo::hevc(payload, size);
-#endif
bool is_key_frame = codec_ok && SrsFlvVideo::keyframe(payload, size) && !SrsFlvVideo::sh(payload, size);
if (!is_key_frame) {
diff --git a/trunk/src/app/srs_app_gb28181.cpp b/trunk/src/app/srs_app_gb28181.cpp
index e9ae2390e..07d6a190a 100644
--- a/trunk/src/app/srs_app_gb28181.cpp
+++ b/trunk/src/app/srs_app_gb28181.cpp
@@ -1571,11 +1571,9 @@ SrsGbMuxer::SrsGbMuxer(SrsGbSession* session)
h264_pps_changed_ = false;
h264_sps_pps_sent_ = false;
-#ifdef SRS_H265
hevc_ = new SrsRawHEVCStream();
vps_sps_pps_sent_ = false;
vps_sps_pps_change_ = false;
-#endif
aac_ = new SrsRawAacStream();
@@ -1588,9 +1586,7 @@ SrsGbMuxer::~SrsGbMuxer()
close();
srs_freep(avc_);
-#ifdef SRS_H265
srs_freep(hevc_);
-#endif
srs_freep(aac_);
srs_freep(queue_);
srs_freep(pprint_);
@@ -1635,12 +1631,10 @@ srs_error_t SrsGbMuxer::on_ts_video(SrsTsMessage* msg, SrsBuffer* avs)
if ((err = mux_h264(msg, avs)) != srs_success){
return srs_error_wrap(err, "mux h264");
}
-#ifdef SRS_H265
} else if (h->ctx_->video_stream_type_ == SrsTsStreamVideoHEVC) {
if ((err = mux_h265(msg, avs)) != srs_success){
return srs_error_wrap(err, "mux hevc");
}
-#endif
} else {
return srs_error_new(ERROR_STREAM_CASTER_TS_CODEC, "ts: unsupported stream codec=%d", h->ctx_->video_stream_type_);
}
@@ -1810,7 +1804,6 @@ srs_error_t SrsGbMuxer::write_h264_ipb_frame(char* frame, int frame_size, uint32
return rtmp_write_packet(SrsFrameTypeVideo, timestamp, flv, nb_flv);
}
-#ifdef SRS_H265
srs_error_t SrsGbMuxer::mux_h265(SrsTsMessage *msg, SrsBuffer *avs)
{
srs_error_t err = srs_success;
@@ -1986,7 +1979,6 @@ srs_error_t SrsGbMuxer::write_h265_ipb_frame(char* frame, int frame_size, uint32
return err;
}
-#endif
srs_error_t SrsGbMuxer::on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs)
{
@@ -2603,12 +2595,6 @@ srs_error_t SrsRecoverablePsContext::decode(SrsBuffer* stream, ISrsPsMessageHand
if ((err = ctx_.decode(stream, handler)) != srs_success) {
return enter_recover_mode(stream, handler, stream->pos(), srs_error_wrap(err, "decode pack"));
}
-#ifndef SRS_H265
- // Check stream type, error if HEVC, because not supported yet.
- if (ctx_.video_stream_type_ == SrsTsStreamVideoHEVC) {
- return srs_error_new(ERROR_GB_PS_HEADER, "HEVC is not supported");
- }
-#endif
return err;
}
diff --git a/trunk/src/app/srs_app_gb28181.hpp b/trunk/src/app/srs_app_gb28181.hpp
index 9049bbd5e..bd9c4dc9f 100644
--- a/trunk/src/app/srs_app_gb28181.hpp
+++ b/trunk/src/app/srs_app_gb28181.hpp
@@ -36,9 +36,7 @@ class SrsGbMuxer;
class SrsSimpleRtmpClient;
struct SrsRawAacStreamCodec;
class SrsRawH264Stream;
-#ifdef SRS_H265
class SrsRawHEVCStream;
-#endif
class SrsSharedPtrMessage;
class SrsPithyPrint;
class SrsRawAacStream;
@@ -469,14 +467,12 @@ private:
bool h264_pps_changed_;
bool h264_sps_pps_sent_;
-#ifdef SRS_H265
SrsRawHEVCStream* hevc_;
bool vps_sps_pps_change_;
std::string h265_vps_;
std::string h265_sps_;
std::string h265_pps_;
bool vps_sps_pps_sent_;
-#endif
private:
SrsRawAacStream* aac_;
std::string aac_specific_config_;
@@ -494,11 +490,9 @@ private:
virtual srs_error_t mux_h264(SrsTsMessage* msg, SrsBuffer* avs);
virtual srs_error_t write_h264_sps_pps(uint32_t dts, uint32_t pts);
virtual srs_error_t write_h264_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts);
-#ifdef SRS_H265
virtual srs_error_t mux_h265(SrsTsMessage* msg, SrsBuffer* avs);
virtual srs_error_t write_h265_vps_sps_pps(uint32_t dts, uint32_t pts);
virtual srs_error_t write_h265_ipb_frame(char* frame, int frame_size, uint32_t dts, uint32_t pts);
-#endif
virtual srs_error_t on_ts_audio(SrsTsMessage* msg, SrsBuffer* avs);
virtual srs_error_t write_audio_raw_frame(char* frame, int frame_size, SrsRawAacStreamCodec* codec, uint32_t dts);
virtual srs_error_t rtmp_write_packet(char type, uint32_t timestamp, char* data, int size);
diff --git a/trunk/src/app/srs_app_rtc_conn.cpp b/trunk/src/app/srs_app_rtc_conn.cpp
index cfa461049..ab090ff6d 100644
--- a/trunk/src/app/srs_app_rtc_conn.cpp
+++ b/trunk/src/app/srs_app_rtc_conn.cpp
@@ -3171,7 +3171,7 @@ srs_error_t SrsRtcConnection::negotiate_play_capability(SrsRtcUserConfig* ruc, s
const SrsMediaPayloadType& payload = payloads.at(j);
// For H.265, we only check if profile-id=1 (Main Profile)
- // Format example: level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST
+ // Format example: level-id=156;profile-id=1;tier-flag=0;tx-mode=SRST
if (!has_main_profile || srs_sdp_has_h265_profile(payload, "1")) {
remote_payload = payload;
break;
diff --git a/trunk/src/app/srs_app_rtc_source.cpp b/trunk/src/app/srs_app_rtc_source.cpp
index 0d5a8d944..82cc40fa8 100644
--- a/trunk/src/app/srs_app_rtc_source.cpp
+++ b/trunk/src/app/srs_app_rtc_source.cpp
@@ -814,16 +814,17 @@ std::vector SrsRtcSource::get_track_desc(std::string ty
if (type == "video") {
std::vector::iterator it = stream_desc_->video_track_descs_.begin();
- while (it != stream_desc_->video_track_descs_.end() ){
+ for (; it != stream_desc_->video_track_descs_.end(); ++it){
+ SrsRtcTrackDescription* track_desc = *it;
+
if (media_name.empty()) {
- track_descs.push_back(*it);
+ track_descs.push_back(track_desc);
} else {
- SrsVideoCodecId codec = SrsVideoCodecId((*it)->media_->codec(true));
+ SrsVideoCodecId codec = SrsVideoCodecId(track_desc->media_->codec(true));
if (codec == srs_video_codec_str2id(media_name)) {
- track_descs.push_back(*it);
+ track_descs.push_back(track_desc);
}
}
- ++it;
}
}
@@ -862,7 +863,7 @@ SrsRtcRtpBuilder::SrsRtcRtpBuilder(SrsFrameToRtcBridge* bridge, SrsSharedPtrvcodec->id == SrsVideoCodecIdHEVC) {
for (size_t i = 0; i < format->vcodec->hevc_dec_conf_record_.nalu_vec.size(); i++) {
- if (format->vcodec->hevc_dec_conf_record_.nalu_vec[i].nal_unit_type == SrsHevcNaluType_VPS
- || format->vcodec->hevc_dec_conf_record_.nalu_vec[i].nal_unit_type == SrsHevcNaluType_SPS
- || format->vcodec->hevc_dec_conf_record_.nalu_vec[i].nal_unit_type == SrsHevcNaluType_PPS) {
- vector& nalu = (vector&)format->vcodec->hevc_dec_conf_record_.nalu_vec[i].nal_data_vec[0].nal_unit_data;
- params.push_back(&nalu);
- size += format->vcodec->hevc_dec_conf_record_.nalu_vec[i].nal_data_vec[0].nal_unit_length;
+ const SrsHevcHvccNalu& nalu = format->vcodec->hevc_dec_conf_record_.nalu_vec[i];
+ if (nalu.nal_unit_type == SrsHevcNaluType_VPS
+ || nalu.nal_unit_type == SrsHevcNaluType_SPS
+ || nalu.nal_unit_type == SrsHevcNaluType_PPS) {
+ const SrsHevcNalData& nal_data = nalu.nal_data_vec[0];
+ params.push_back(&(vector&)nal_data.nal_unit_data);
+ size += nal_data.nal_unit_length;
}
}
@@ -2703,7 +2705,7 @@ srs_error_t SrsVideoPayload::set_h264_param_desc(std::string fmtp)
return err;
}
-// level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST
+// level-id=156;profile-id=1;tier-flag=0;tx-mode=SRST
srs_error_t SrsVideoPayload::set_h265_param_desc(std::string fmtp)
{
std::vector attributes = split_str(fmtp, ";");
diff --git a/trunk/src/app/srs_app_source.cpp b/trunk/src/app/srs_app_source.cpp
index c17f85f2b..b3a4d89d4 100755
--- a/trunk/src/app/srs_app_source.cpp
+++ b/trunk/src/app/srs_app_source.cpp
@@ -623,9 +623,7 @@ srs_error_t SrsGopCache::cache(SrsSharedPtrMessage* shared_msg)
if (msg->is_video()) {
// Drop video when not h.264 or h.265.
bool codec_ok = SrsFlvVideo::h264(msg->payload, msg->size);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : SrsFlvVideo::hevc(msg->payload, msg->size);
-#endif
if (!codec_ok) return err;
cached_video_count++;
@@ -1046,13 +1044,11 @@ srs_error_t SrsOriginHub::on_video(SrsSharedPtrMessage* shared_video, bool is_se
srs_trace("%dB video sh, codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %.1ffps, %.1fs)",
msg->size, c->id, srs_avc_profile2str(c->avc_profile).c_str(), srs_avc_level2str(c->avc_level).c_str(),
c->width, c->height, c->video_data_rate / 1000, c->frame_rate, c->duration);
-#ifdef SRS_H265
} else if (c->id == SrsVideoCodecIdHEVC) {
err = stat->on_video_info(req_, c->id, c->hevc_profile, c->hevc_level, c->width, c->height);
srs_trace("%dB video sh, codec(%d, profile=%s, level=%s, %dx%d, %dkbps, %.1ffps, %.1fs)",
msg->size, c->id, srs_hevc_profile2str(c->hevc_profile).c_str(), srs_hevc_level2str(c->hevc_level).c_str(),
c->width, c->height, c->video_data_rate / 1000, c->frame_rate, c->duration);
-#endif
}
if (err != srs_success) {
return srs_error_wrap(err, "stat video");
diff --git a/trunk/src/app/srs_app_srt_source.cpp b/trunk/src/app/srs_app_srt_source.cpp
index 860cd01e1..01dd2dc9b 100644
--- a/trunk/src/app/srs_app_srt_source.cpp
+++ b/trunk/src/app/srs_app_srt_source.cpp
@@ -372,13 +372,11 @@ srs_error_t SrsSrtFrameBuilder::on_ts_message(SrsTsMessage* msg)
}
// TODO: FIXME: implements other codec?
-#ifdef SRS_H265
if (msg->channel->stream == SrsTsStreamVideoHEVC) {
if ((err = on_ts_video_hevc(msg, &avs)) != srs_success) {
return srs_error_wrap(err, "ts: consume hevc video");
}
}
-#endif
return err;
}
@@ -555,7 +553,6 @@ srs_error_t SrsSrtFrameBuilder::on_h264_frame(SrsTsMessage* msg, vector >& ipb_frames);
srs_error_t check_audio_sh_change(SrsTsMessage* msg, uint32_t pts);
srs_error_t on_aac_frame(SrsTsMessage* msg, uint32_t pts, char* frame, int frame_size);
-#ifdef SRS_H265
srs_error_t on_ts_video_hevc(SrsTsMessage *msg, SrsBuffer *avs);
srs_error_t check_vps_sps_pps_change(SrsTsMessage *msg);
srs_error_t on_hevc_frame(SrsTsMessage *msg, std::vector< std::pair > &ipb_frames);
-#endif
private:
ISrsStreamBridge* bridge_;
private:
@@ -135,12 +133,10 @@ private:
bool sps_pps_change_;
std::string sps_;
std::string pps_;
-#ifdef SRS_H265
bool vps_sps_pps_change_;
std::string hevc_vps_;
std::string hevc_sps_;
std::vector hevc_pps_;
-#endif
// Record audio sepcific config had changed, if change, need to generate new audio sh frame.
bool audio_sh_change_;
std::string audio_sh_;
diff --git a/trunk/src/app/srs_app_statistic.cpp b/trunk/src/app/srs_app_statistic.cpp
index 57e09063b..d30f10ffd 100644
--- a/trunk/src/app/srs_app_statistic.cpp
+++ b/trunk/src/app/srs_app_statistic.cpp
@@ -147,11 +147,9 @@ srs_error_t SrsStatisticStream::dumps(SrsJsonObject* obj)
if (vcodec == SrsVideoCodecIdAVC) {
video->set("profile", SrsJsonAny::str(srs_avc_profile2str(avc_profile).c_str()));
video->set("level", SrsJsonAny::str(srs_avc_level2str(avc_level).c_str()));
-#ifdef SRS_H265
} else if (vcodec == SrsVideoCodecIdHEVC) {
video->set("profile", SrsJsonAny::str(srs_hevc_profile2str(hevc_profile).c_str()));
video->set("level", SrsJsonAny::str(srs_hevc_level2str(hevc_level).c_str()));
-#endif
} else {
video->set("profile", SrsJsonAny::str("Other"));
video->set("level", SrsJsonAny::str("Other"));
@@ -360,11 +358,9 @@ srs_error_t SrsStatistic::on_video_info(SrsRequest* req, SrsVideoCodecId vcodec,
if (vcodec == SrsVideoCodecIdAVC) {
stream->avc_profile = (SrsAvcProfile)profile;
stream->avc_level = (SrsAvcLevel)level;
-#ifdef SRS_H265
} else if (vcodec == SrsVideoCodecIdHEVC) {
stream->hevc_profile = (SrsHevcProfile)profile;
stream->hevc_level = (SrsHevcLevel)level;
-#endif
} else {
stream->avc_profile = (SrsAvcProfile)profile;
stream->avc_level = (SrsAvcLevel)level;
@@ -664,7 +660,6 @@ void SrsStatistic::dumps_hints_kv(std::stringstream & ss)
ss << "&send=" << kbps->get_send_kbps_30s();
}
-#ifdef SRS_H265
// For HEVC, we should check active stream which is HEVC codec.
for (std::map::iterator it = streams.begin(); it != streams.end(); it++) {
SrsStatisticStream* stream = it->second;
@@ -673,7 +668,6 @@ void SrsStatistic::dumps_hints_kv(std::stringstream & ss)
break;
}
}
-#endif
}
#ifdef SRS_APM
diff --git a/trunk/src/app/srs_app_statistic.hpp b/trunk/src/app/srs_app_statistic.hpp
index e15a0c702..656a0bc27 100644
--- a/trunk/src/app/srs_app_statistic.hpp
+++ b/trunk/src/app/srs_app_statistic.hpp
@@ -70,12 +70,10 @@ public:
SrsAvcProfile avc_profile;
// The level_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
SrsAvcLevel avc_level;
-#ifdef SRS_H265
// The profile_idc, ITU-T-H.265-2021.pdf, page 62.
SrsHevcProfile hevc_profile;
// The level_idc, ITU-T-H.265-2021.pdf, page 63.
SrsHevcLevel hevc_level;
-#endif
// The width and height in codec info.
int width;
int height;
diff --git a/trunk/src/app/srs_app_stream_bridge.cpp b/trunk/src/app/srs_app_stream_bridge.cpp
index 1a06ce365..cc9bf0e89 100644
--- a/trunk/src/app/srs_app_stream_bridge.cpp
+++ b/trunk/src/app/srs_app_stream_bridge.cpp
@@ -68,6 +68,7 @@ SrsFrameToRtcBridge::SrsFrameToRtcBridge(SrsSharedPtr source)
source_ = source;
#if defined(SRS_FFMPEG_FIT)
+ // Use lazy initialization - no need to determine codec/track parameters here
rtp_builder_ = new SrsRtcRtpBuilder(this, source);
#endif
}
@@ -131,8 +132,6 @@ srs_error_t SrsFrameToRtcBridge::on_rtp(SrsRtpPacket* pkt)
return source_->on_rtp(pkt);
}
-
-
#endif
SrsCompositeBridge::SrsCompositeBridge()
diff --git a/trunk/src/core/srs_core_version7.hpp b/trunk/src/core/srs_core_version7.hpp
index a836beea1..5a48c9b2f 100644
--- a/trunk/src/core/srs_core_version7.hpp
+++ b/trunk/src/core/srs_core_version7.hpp
@@ -9,6 +9,6 @@
#define VERSION_MAJOR 7
#define VERSION_MINOR 0
-#define VERSION_REVISION 44
+#define VERSION_REVISION 45
#endif
\ No newline at end of file
diff --git a/trunk/src/kernel/srs_kernel_codec.cpp b/trunk/src/kernel/srs_kernel_codec.cpp
index bcb516438..22a178c4e 100644
--- a/trunk/src/kernel/srs_kernel_codec.cpp
+++ b/trunk/src/kernel/srs_kernel_codec.cpp
@@ -206,9 +206,7 @@ bool SrsFlvVideo::sh(char* data, int size)
{
// Check sequence header only for H.264 or H.265
bool codec_ok = h264(data, size);
-#ifdef SRS_H265
codec_ok = codec_ok? true : hevc(data, size);
-#endif
if (!codec_ok) return false;
// 2bytes required.
@@ -247,7 +245,6 @@ bool SrsFlvVideo::h264(char* data, int size)
return codec_id == SrsVideoCodecIdAVC;
}
-#ifdef SRS_H265
bool SrsFlvVideo::hevc(char* data, int size)
{
// 1bytes required.
@@ -276,7 +273,6 @@ bool SrsFlvVideo::hevc(char* data, int size)
return codec_id == SrsVideoCodecIdHEVC;
}
-#endif
bool SrsFlvVideo::acceptable(char* data, int size)
{
@@ -505,8 +501,6 @@ string srs_avc_level2str(SrsAvcLevel level)
}
}
-#ifdef SRS_H265
-
string srs_hevc_profile2str(SrsHevcProfile profile)
{
switch (profile) {
@@ -538,8 +532,6 @@ string srs_hevc_level2str(SrsHevcLevel level)
}
}
-#endif
-
SrsSample::SrsSample()
{
size = 0;
@@ -705,13 +697,9 @@ srs_error_t SrsVideoFrame::add_sample(char* bytes, int size)
// For HEVC(H.265), try to parse the IDR from NALUs.
if (c && c->id == SrsVideoCodecIdHEVC) {
-#ifdef SRS_H265
SrsHevcNaluType nalu_type = SrsHevcNaluTypeParse(bytes[0]);
has_idr = SrsIsIRAP(nalu_type);
return err;
-#else
- return srs_error_new(ERROR_HEVC_DISABLED, "H.265 is disabled");
-#endif
}
// By default, use AVC(H.264) to parse NALU.
@@ -791,7 +779,6 @@ srs_error_t SrsVideoFrame::parse_avc_bframe(const SrsSample* sample, bool& is_b_
return err;
}
-#ifdef SRS_H265
srs_error_t SrsVideoFrame::parse_hevc_nalu_type(const SrsSample* sample, SrsHevcNaluType& hevc_nalu_type)
{
srs_error_t err = srs_success;
@@ -872,7 +859,6 @@ srs_error_t SrsVideoFrame::parse_hevc_bframe(const SrsSample* sample, SrsFormat
return err;
}
-#endif
SrsFormat::SrsFormat()
{
@@ -1094,9 +1080,7 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
// Check codec for H.264 and H.265.
bool codec_ok = (codec_id == SrsVideoCodecIdAVC);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (codec_id == SrsVideoCodecIdHEVC);
-#endif
if (!codec_ok) {
return srs_error_new(ERROR_HLS_DECODE_ERROR, "only support video H.264/H.265, actual=%d", codec_id);
}
@@ -1131,7 +1115,6 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
// Parse sequence header for H.265/HEVC.
if (codec_id == SrsVideoCodecIdHEVC) {
-#ifdef SRS_H265
if (packet_type == SrsVideoAvcFrameTraitSequenceHeader) {
// TODO: demux vps/sps/pps for hevc
if ((err = hevc_demux_hvcc(stream)) != srs_success) {
@@ -1144,9 +1127,6 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
}
}
return err;
-#else
- return srs_error_new(ERROR_HEVC_DISABLED, "H.265 is disabled");
-#endif
}
// Parse sequence header for H.264/AVC.
@@ -1169,7 +1149,6 @@ srs_error_t SrsFormat::video_avc_demux(SrsBuffer* stream, int64_t timestamp)
// For media server, we don't care the codec, so we just try to parse sps-pps, and we could ignore any error if fail.
// LCOV_EXCL_START
-#ifdef SRS_H265
// struct ptl
SrsHevcProfileTierLevel::SrsHevcProfileTierLevel()
{
@@ -2257,8 +2236,6 @@ srs_error_t SrsFormat::hevc_demux_rbsp_ptl(SrsBitBuffer* bs, SrsHevcProfileTierL
return err;
}
-#endif
-
srs_error_t SrsFormat::avc_demux_sps_pps(SrsBuffer* stream)
{
// AVCDecoderConfigurationRecord
@@ -2615,12 +2592,8 @@ srs_error_t SrsFormat::video_nalu_demux(SrsBuffer* stream)
}
if (vcodec->id == SrsVideoCodecIdHEVC) {
-#ifdef SRS_H265
// TODO: FIXME: Might need to guess format?
return do_avc_demux_ibmf_format(stream);
-#else
- return srs_error_new(ERROR_HEVC_DISABLED, "H.265 is disabled");
-#endif
}
// Parse the SPS/PPS in ANNEXB or IBMF format.
diff --git a/trunk/src/kernel/srs_kernel_codec.hpp b/trunk/src/kernel/srs_kernel_codec.hpp
index b2f2b00b8..638bacd60 100644
--- a/trunk/src/kernel/srs_kernel_codec.hpp
+++ b/trunk/src/kernel/srs_kernel_codec.hpp
@@ -297,10 +297,8 @@ public:
* check codec h264.
*/
static bool h264(char* data, int size);
-#ifdef SRS_H265
// Check whether codec is HEVC(H.265).
static bool hevc(char* data, int size);
-#endif
/**
* check the video RTMP/flv header info,
* @return true if video RTMP/flv header is ok.
@@ -439,7 +437,6 @@ enum SrsAvcNaluType
#define SrsAvcNaluTypeParse(code) (SrsAvcNaluType)(code & 0x1F)
std::string srs_avc_nalu2str(SrsAvcNaluType nalu_type);
-#ifdef SRS_H265
/**
* The enum NALU type for HEVC
* @see Table 7-1 – NAL unit type codes and NAL unit type classes
@@ -975,8 +972,6 @@ struct SrsHevcDecoderConfigurationRecord
SrsHevcRbspPps pps_table[SrsHevcMax_PPS_COUNT];
};
-#endif
-
/**
* Table 7-6 – Name association to slice_type
* ISO_IEC_14496-10-AVC-2012.pdf, page 105.
@@ -1100,8 +1095,6 @@ enum SrsAvcLevel
};
std::string srs_avc_level2str(SrsAvcLevel level);
-#ifdef SRS_H265
-
/**
* the profile for hevc/h.265, Annex A Profiles, tiers and levels
* @see A.3 Profiles
@@ -1144,8 +1137,6 @@ enum SrsHevcLevel
};
std::string srs_hevc_level2str(SrsHevcLevel level);
-#endif
-
/**
* A sample is the unit of frame.
* It's a NALU for H.264, H.265.
@@ -1256,12 +1247,10 @@ public:
SrsAvcProfile avc_profile;
// level_idc, ISO_IEC_14496-10-AVC-2003.pdf, page 45.
SrsAvcLevel avc_level;
-#ifdef SRS_H265
// The profile_idc, ITU-T-H.265-2021.pdf, page 62.
SrsHevcProfile hevc_profile;
// The level_idc, ITU-T-H.265-2021.pdf, page 63.
SrsHevcLevel hevc_level;
-#endif
// lengthSizeMinusOne, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
int8_t NAL_unit_length;
// Note that we may resize the vector, so the under-layer bytes may change.
@@ -1270,10 +1259,8 @@ public:
public:
// the avc payload format.
SrsAvcPayloadFormat payload_format;
-#ifdef SRS_H265
public:
SrsHevcDecoderConfigurationRecord hevc_dec_conf_record_;
-#endif
public:
SrsVideoCodecConfig();
virtual ~SrsVideoCodecConfig();
@@ -1349,10 +1336,8 @@ public:
public:
static srs_error_t parse_avc_nalu_type(const SrsSample* sample, SrsAvcNaluType& avc_nalu_type);
static srs_error_t parse_avc_bframe(const SrsSample* sample, bool& is_b_frame);
-#ifdef SRS_H265
static srs_error_t parse_hevc_nalu_type(const SrsSample* sample, SrsHevcNaluType& hevc_nalu_type);
static srs_error_t parse_hevc_bframe(const SrsSample* sample, SrsFormat* format, bool& is_b_frame);
-#endif
};
/**
@@ -1400,7 +1385,6 @@ private:
// Demux the sps/pps from sequence header.
// Demux the samples from NALUs.
virtual srs_error_t video_avc_demux(SrsBuffer* stream, int64_t timestamp);
-#ifdef SRS_H265
private:
virtual srs_error_t hevc_demux_hvcc(SrsBuffer* stream);
private:
@@ -1413,7 +1397,6 @@ public:
virtual srs_error_t hevc_demux_vps(SrsBuffer *stream);
virtual srs_error_t hevc_demux_sps(SrsBuffer *stream);
virtual srs_error_t hevc_demux_pps(SrsBuffer *stream);
-#endif
private:
// Parse the H.264 SPS/PPS.
virtual srs_error_t avc_demux_sps_pps(SrsBuffer* stream);
diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp
index d2ab5a49a..885191df2 100644
--- a/trunk/src/kernel/srs_kernel_rtc_rtp.cpp
+++ b/trunk/src/kernel/srs_kernel_rtc_rtp.cpp
@@ -1568,7 +1568,6 @@ ISrsRtpPayloader* SrsRtpFUAPayload2::copy()
return cp;
}
-#ifdef SRS_H265
SrsRtpSTAPPayloadHevc::SrsRtpSTAPPayloadHevc()
{
++_srs_pps_objs_rothers->sugar;
@@ -1927,4 +1926,4 @@ ISrsRtpPayloader* SrsRtpFUAPayloadHevc2::copy()
return cp;
}
-#endif
\ No newline at end of file
+
diff --git a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp
index f69732b3c..09d48008b 100644
--- a/trunk/src/kernel/srs_kernel_rtc_rtp.hpp
+++ b/trunk/src/kernel/srs_kernel_rtc_rtp.hpp
@@ -478,7 +478,6 @@ public:
virtual ISrsRtpPayloader* copy();
};
-#ifdef SRS_H265
class SrsRtpSTAPPayloadHevc : public ISrsRtpPayloader
{
public:
@@ -542,6 +541,5 @@ public:
virtual srs_error_t decode(SrsBuffer* buf);
virtual ISrsRtpPayloader* copy();
};
-#endif
#endif
diff --git a/trunk/src/kernel/srs_kernel_ts.cpp b/trunk/src/kernel/srs_kernel_ts.cpp
index 9492852fb..73293a07a 100644
--- a/trunk/src/kernel/srs_kernel_ts.cpp
+++ b/trunk/src/kernel/srs_kernel_ts.cpp
@@ -43,9 +43,7 @@ string srs_ts_stream2string(SrsTsStream stream)
case SrsTsStreamAudioAC3: return "AC3";
case SrsTsStreamAudioDTS: return "AudioDTS";
case SrsTsStreamVideoH264: return "H.264";
-#ifdef SRS_H265
case SrsTsStreamVideoHEVC: return "H.265";
-#endif
case SrsTsStreamVideoMpeg4: return "MP4";
case SrsTsStreamAudioMpeg4: return "MP4A";
default: return "Other";
@@ -290,13 +288,9 @@ srs_error_t SrsTsContext::encode(ISrsStreamWriter* writer, SrsTsMessage* msg, Sr
video_pid = TS_VIDEO_AVC_PID;
break;
case SrsVideoCodecIdHEVC:
-#ifdef SRS_H265
vs = SrsTsStreamVideoHEVC;
video_pid = TS_VIDEO_AVC_PID;
break;
-#else
- return srs_error_new(ERROR_HEVC_DISABLED, "H.265 is disabled");
-#endif
case SrsVideoCodecIdDisabled:
vs = SrsTsStreamReserved;
break;
@@ -371,9 +365,7 @@ srs_error_t SrsTsContext::encode_pat_pmt(ISrsStreamWriter* writer, int16_t vpid,
srs_error_t err = srs_success;
bool codec_ok = (vs == SrsTsStreamVideoH264 || as == SrsTsStreamAudioAAC || as == SrsTsStreamAudioMp3);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (vs == SrsTsStreamVideoHEVC);
-#endif
if (!codec_ok) {
return srs_error_new(ERROR_HLS_NO_STREAM, "ts: no PID, vs=%d, as=%d", vs, as);
}
@@ -441,9 +433,7 @@ srs_error_t SrsTsContext::encode_pes(ISrsStreamWriter* writer, SrsTsMessage* msg
}
bool codec_ok = (sid == SrsTsStreamVideoH264 || sid == SrsTsStreamAudioAAC || sid == SrsTsStreamAudioMp3);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (sid == SrsTsStreamVideoHEVC);
-#endif
if (!codec_ok) {
srs_info("ts: ignore the unknown stream, sid=%d", sid);
return err;
@@ -770,9 +760,7 @@ SrsTsPacket* SrsTsPacket::create_pmt(SrsTsContext* context,
// Here we must get the correct codec.
bool codec_ok = (vs == SrsTsStreamVideoH264 || as == SrsTsStreamAudioAAC || as == SrsTsStreamAudioMp3);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (vs == SrsTsStreamVideoHEVC);
-#endif
srs_assert(codec_ok);
// if mp3 or aac specified, use audio to carry pcr.
@@ -785,9 +773,7 @@ SrsTsPacket* SrsTsPacket::create_pmt(SrsTsContext* context,
// If h.264/h.265 specified, use video to carry pcr.
codec_ok = (vs == SrsTsStreamVideoH264);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (vs == SrsTsStreamVideoHEVC);
-#endif
if (codec_ok) {
pmt->PCR_PID = vpid;
pmt->infos.push_back(new SrsTsPayloadPMTESInfo(vs, vpid));
@@ -2563,9 +2549,7 @@ srs_error_t SrsTsPayloadPMT::psi_decode(SrsBuffer* stream)
// update the apply pid table
switch (info->stream_type) {
case SrsTsStreamVideoH264:
-#ifdef SRS_H265
case SrsTsStreamVideoHEVC:
-#endif
case SrsTsStreamVideoMpeg4:
packet->context->set(info->elementary_PID, SrsTsPidApplyVideo, info->stream_type);
break;
@@ -2649,9 +2633,7 @@ srs_error_t SrsTsPayloadPMT::psi_encode(SrsBuffer* stream)
// update the apply pid table
switch (info->stream_type) {
case SrsTsStreamVideoH264:
-#ifdef SRS_H265
case SrsTsStreamVideoHEVC:
-#endif
case SrsTsStreamVideoMpeg4:
packet->context->set(info->elementary_PID, SrsTsPidApplyVideo, info->stream_type);
break;
@@ -2884,11 +2866,7 @@ srs_error_t SrsTsMessageCache::cache_video(SrsVideoFrame* frame, int64_t dts)
// Write H.265 video frame to cache.
if (frame && frame->vcodec()->id == SrsVideoCodecIdHEVC) {
-#ifdef SRS_H265
return do_cache_hevc(frame);
-#else
- return srs_error_new(ERROR_HEVC_DISABLED, "H.265 is disabled");
-#endif
}
// Write H.264 video frame to cache.
@@ -3122,7 +3100,6 @@ srs_error_t SrsTsMessageCache::do_cache_avc(SrsVideoFrame* frame)
return err;
}
-#ifdef SRS_H265
srs_error_t SrsTsMessageCache::do_cache_hevc(SrsVideoFrame* frame)
{
srs_error_t err = srs_success;
@@ -3165,7 +3142,6 @@ srs_error_t SrsTsMessageCache::do_cache_hevc(SrsVideoFrame* frame)
return err;
}
-#endif
SrsTsTransmuxer::SrsTsTransmuxer()
{
@@ -3306,9 +3282,7 @@ srs_error_t SrsTsTransmuxer::write_video(int64_t timestamp, char* data, int size
}
bool codec_ok = (format->vcodec->id == SrsVideoCodecIdAVC);
-#ifdef SRS_H265
codec_ok = codec_ok ? true : (format->vcodec->id == SrsVideoCodecIdHEVC);
-#endif
if (!codec_ok) {
return err;
}
diff --git a/trunk/src/kernel/srs_kernel_ts.hpp b/trunk/src/kernel/srs_kernel_ts.hpp
index b072299c2..b25558e7c 100644
--- a/trunk/src/kernel/srs_kernel_ts.hpp
+++ b/trunk/src/kernel/srs_kernel_ts.hpp
@@ -1321,9 +1321,7 @@ private:
virtual srs_error_t do_cache_mp3(SrsAudioFrame* frame);
virtual srs_error_t do_cache_aac(SrsAudioFrame* frame);
virtual srs_error_t do_cache_avc(SrsVideoFrame* frame);
-#ifdef SRS_H265
virtual srs_error_t do_cache_hevc(SrsVideoFrame* frame);
-#endif
};
// Transmux the RTMP stream to HTTP-TS stream.
diff --git a/trunk/src/protocol/srs_protocol_raw_avc.cpp b/trunk/src/protocol/srs_protocol_raw_avc.cpp
index bc22e2520..f89753d36 100644
--- a/trunk/src/protocol/srs_protocol_raw_avc.cpp
+++ b/trunk/src/protocol/srs_protocol_raw_avc.cpp
@@ -261,8 +261,6 @@ srs_error_t SrsRawH264Stream::mux_avc2flv(string video, int8_t frame_type, int8_
return err;
}
-#ifdef SRS_H265
-
SrsRawHEVCStream::SrsRawHEVCStream()
{
}
@@ -616,8 +614,6 @@ srs_error_t SrsRawHEVCStream::mux_avc2flv_enhanced(std::string video, int8_t fra
return err;
}
-#endif
-
SrsRawAacStream::SrsRawAacStream()
{
}
diff --git a/trunk/src/protocol/srs_protocol_raw_avc.hpp b/trunk/src/protocol/srs_protocol_raw_avc.hpp
index e9402cc56..bec8bda1c 100644
--- a/trunk/src/protocol/srs_protocol_raw_avc.hpp
+++ b/trunk/src/protocol/srs_protocol_raw_avc.hpp
@@ -53,7 +53,6 @@ public:
virtual srs_error_t mux_avc2flv(std::string video, int8_t frame_type, int8_t avc_packet_type, uint32_t dts, uint32_t pts, char** flv, int* nb_flv);
};
-#ifdef SRS_H265
// The raw h.265 stream, in annexb.
class SrsRawHEVCStream
{
@@ -105,7 +104,6 @@ public:
// This affects other modules like SRT and GB28181, so should be done in a separate refactoring.
virtual srs_error_t mux_avc2flv_enhanced(std::string video, int8_t frame_type, int8_t packet_type, uint32_t dts, uint32_t pts, char **flv, int *nb_flv);
};
-#endif
// The header of adts sample.
struct SrsRawAacStreamCodec
diff --git a/trunk/src/utest/srs_utest_avc.cpp b/trunk/src/utest/srs_utest_avc.cpp
index c05dea38c..464f63874 100644
--- a/trunk/src/utest/srs_utest_avc.cpp
+++ b/trunk/src/utest/srs_utest_avc.cpp
@@ -600,8 +600,6 @@ VOID TEST(SrsAVCTest, AACMuxToFLV)
}
}
-#ifdef SRS_H265
-
VOID TEST(SrsAVCTest, HevcMultiPPS)
{
srs_error_t err;
@@ -686,5 +684,3 @@ VOID TEST(SrsAVCTest, HevcMultiPPS)
EXPECT_TRUE(stream.empty());
}
-#endif
-
diff --git a/trunk/src/utest/srs_utest_kernel.cpp b/trunk/src/utest/srs_utest_kernel.cpp
index 7b0b51a65..9caebc1df 100644
--- a/trunk/src/utest/srs_utest_kernel.cpp
+++ b/trunk/src/utest/srs_utest_kernel.cpp
@@ -3656,7 +3656,6 @@ VOID TEST(KernelCodecTest, VideoFrameH264)
}
}
-#ifdef SRS_H265
VOID TEST(KernelCodecTest, VideoFrameH265)
{
srs_error_t err;
@@ -3764,7 +3763,6 @@ VOID TEST(KernelCodecTest, VideoFrameH265)
HELPER_EXPECT_FAILED(SrsVideoFrame::parse_hevc_bframe(&empty_sample, &format, is_b_frame));
}
}
-#endif
VOID TEST(KernelCodecTest, IsSequenceHeaderSpecial)
{
@@ -4261,7 +4259,6 @@ VOID TEST(KernelCodecTest, VideoFormat)
}
}
-#ifdef SRS_H265
VOID TEST(KernelCodecTest, HevcVideoFormat)
{
srs_error_t err;
@@ -4454,7 +4451,6 @@ VOID TEST(KernelCodecTest, HevcVideoFormat)
EXPECT_EQ(1, f.video->nb_samples);
}
}
-#endif
VOID TEST(KernelFileTest, FileWriteReader)
{
@@ -5735,17 +5731,6 @@ VOID TEST(KernelTSTest, CoverContextEncodeHEVC)
SrsTsContext ctx;
MockTsHandler h;
-#ifndef SRS_H265
- if (true) {
- MockSrsFileWriter f;
- SrsTsMessage m;
-
- err = ctx.encode(&f, &m, SrsVideoCodecIdHEVC, SrsAudioCodecIdOpus);
- HELPER_EXPECT_FAILED(err);
- }
-#endif
-
-#ifdef SRS_H265
if (true) {
MockSrsFileWriter f;
SrsTsMessage m;
@@ -5753,7 +5738,6 @@ VOID TEST(KernelTSTest, CoverContextEncodeHEVC)
err = ctx.encode(&f, &m, SrsVideoCodecIdHEVC, SrsAudioCodecIdOpus);
HELPER_EXPECT_SUCCESS(err);
}
-#endif
}
VOID TEST(KernelTSTest, CoverContextDecode)
diff --git a/trunk/src/utest/srs_utest_kernel2.cpp b/trunk/src/utest/srs_utest_kernel2.cpp
index 72da83bb9..3e059010f 100644
--- a/trunk/src/utest/srs_utest_kernel2.cpp
+++ b/trunk/src/utest/srs_utest_kernel2.cpp
@@ -426,8 +426,7 @@ VOID TEST(KernelRTMPExtTest, ExtRTMPTest)
EXPECT_EQ(SrsVideoAvcFrameTraitNALU, f.video->avc_packet_type);
EXPECT_EQ(0x12, f.video->cts);
}
-
-#ifdef SRS_H265
+
// For new RTMP enhanced specification, with ext tag header.
if (true) {
SrsFormat f;
@@ -481,7 +480,6 @@ VOID TEST(KernelRTMPExtTest, ExtRTMPTest)
HELPER_ASSERT_SUCCESS(f.initialize());
HELPER_EXPECT_FAILED(f.on_video(0, (char*) "\x93mvc1", 5));
}
-#endif
}
VOID TEST(KernelCodecTest, VideoFormatSepcialMProtect_DJI_M30)
diff --git a/trunk/src/utest/srs_utest_rtc.cpp b/trunk/src/utest/srs_utest_rtc.cpp
index 9603c512c..92014492c 100644
--- a/trunk/src/utest/srs_utest_rtc.cpp
+++ b/trunk/src/utest/srs_utest_rtc.cpp
@@ -1365,3 +1365,632 @@ VOID TEST(KernelRTCTest, JitterSequence)
EXPECT_EQ((uint32_t)11, jitter.correct(11));
}
+VOID TEST(KernelRTCTest, H265SDPParsing)
+{
+ srs_error_t err;
+
+ // Test srs_parse_h265_fmtp with valid parameters
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST";
+
+ HELPER_EXPECT_SUCCESS(srs_parse_h265_fmtp(fmtp, h265_param));
+ EXPECT_STREQ("180", h265_param.level_id.c_str());
+ EXPECT_STREQ("1", h265_param.profile_id.c_str());
+ EXPECT_STREQ("0", h265_param.tier_flag.c_str());
+ EXPECT_STREQ("SRST", h265_param.tx_mode.c_str());
+ }
+
+ // Test srs_parse_h265_fmtp with different parameter order
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "profile-id=2;tier-flag=1;level-id=93;tx-mode=MCTS";
+
+ HELPER_EXPECT_SUCCESS(srs_parse_h265_fmtp(fmtp, h265_param));
+ EXPECT_STREQ("93", h265_param.level_id.c_str());
+ EXPECT_STREQ("2", h265_param.profile_id.c_str());
+ EXPECT_STREQ("1", h265_param.tier_flag.c_str());
+ EXPECT_STREQ("MCTS", h265_param.tx_mode.c_str());
+ }
+
+ // Test srs_parse_h265_fmtp with missing level-id (should fail)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "profile-id=1;tier-flag=0;tx-mode=SRST";
+
+ HELPER_EXPECT_FAILED(srs_parse_h265_fmtp(fmtp, h265_param));
+ }
+
+ // Test srs_parse_h265_fmtp with missing profile-id (should fail)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "level-id=180;tier-flag=0;tx-mode=SRST";
+
+ HELPER_EXPECT_FAILED(srs_parse_h265_fmtp(fmtp, h265_param));
+ }
+
+ // Test srs_parse_h265_fmtp with missing tier-flag (should fail)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "level-id=180;profile-id=1;tx-mode=SRST";
+
+ HELPER_EXPECT_FAILED(srs_parse_h265_fmtp(fmtp, h265_param));
+ }
+
+ // Test srs_parse_h265_fmtp with missing tx-mode (should fail)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "level-id=180;profile-id=1;tier-flag=0";
+
+ HELPER_EXPECT_FAILED(srs_parse_h265_fmtp(fmtp, h265_param));
+ }
+
+ // Test srs_parse_h265_fmtp with empty string (should fail)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "";
+
+ HELPER_EXPECT_FAILED(srs_parse_h265_fmtp(fmtp, h265_param));
+ }
+
+ // Test srs_parse_h265_fmtp with extra unknown parameters (should succeed)
+ if (true) {
+ H265SpecificParam h265_param;
+ string fmtp = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST;unknown-param=value";
+
+ HELPER_EXPECT_SUCCESS(srs_parse_h265_fmtp(fmtp, h265_param));
+ EXPECT_STREQ("180", h265_param.level_id.c_str());
+ EXPECT_STREQ("1", h265_param.profile_id.c_str());
+ EXPECT_STREQ("0", h265_param.tier_flag.c_str());
+ EXPECT_STREQ("SRST", h265_param.tx_mode.c_str());
+ }
+}
+
+// Forward declarations for H.265 SDP functions (defined in srs_app_rtc_conn.cpp)
+extern bool srs_sdp_has_h265_profile(const SrsMediaPayloadType& payload_type, const string& profile);
+extern bool srs_sdp_has_h265_profile(const SrsSdp& sdp, const string& profile);
+
+VOID TEST(KernelRTCTest, H265SDPProfileChecking)
+{
+ // Test srs_sdp_has_h265_profile with payload type
+ if (true) {
+ SrsMediaPayloadType payload_type(96);
+ payload_type.format_specific_param_ = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST";
+
+ // Should find Main Profile (profile-id=1)
+ EXPECT_TRUE(srs_sdp_has_h265_profile(payload_type, "1"));
+
+ // Should not find other profiles
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "2"));
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "3"));
+ }
+
+ // Test srs_sdp_has_h265_profile with different profile
+ if (true) {
+ SrsMediaPayloadType payload_type(97);
+ payload_type.format_specific_param_ = "level-id=93;profile-id=2;tier-flag=1;tx-mode=MCTS";
+
+ // Should find Main 10 Profile (profile-id=2)
+ EXPECT_TRUE(srs_sdp_has_h265_profile(payload_type, "2"));
+
+ // Should not find Main Profile
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "1"));
+ }
+
+ // Test srs_sdp_has_h265_profile with empty format_specific_param_
+ if (true) {
+ SrsMediaPayloadType payload_type(98);
+ payload_type.format_specific_param_ = "";
+
+ // Should not find any profile
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "1"));
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "2"));
+ }
+
+ // Test srs_sdp_has_h265_profile with invalid format_specific_param_
+ if (true) {
+ SrsMediaPayloadType payload_type(99);
+ payload_type.format_specific_param_ = "invalid-format";
+
+ // Should not find any profile (parsing should fail gracefully)
+ EXPECT_FALSE(srs_sdp_has_h265_profile(payload_type, "1"));
+ }
+
+ // Test srs_sdp_has_h265_profile with SDP containing H.265
+ if (true) {
+ SrsSdp sdp;
+ SrsMediaDesc video_desc("video");
+
+ SrsMediaPayloadType h265_payload(96);
+ h265_payload.encoding_name_ = "H265";
+ h265_payload.format_specific_param_ = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST";
+ video_desc.payload_types_.push_back(h265_payload);
+
+ sdp.media_descs_.push_back(video_desc);
+
+ // Should find Main Profile in SDP
+ EXPECT_TRUE(srs_sdp_has_h265_profile(sdp, "1"));
+ EXPECT_FALSE(srs_sdp_has_h265_profile(sdp, "2"));
+ }
+
+ // Test srs_sdp_has_h265_profile with SDP containing no H.265
+ if (true) {
+ SrsSdp sdp;
+ SrsMediaDesc video_desc("video");
+
+ SrsMediaPayloadType h264_payload(96);
+ h264_payload.encoding_name_ = "H264";
+ h264_payload.format_specific_param_ = "profile-level-id=42e01f";
+ video_desc.payload_types_.push_back(h264_payload);
+
+ sdp.media_descs_.push_back(video_desc);
+
+ // Should not find any H.265 profile
+ EXPECT_FALSE(srs_sdp_has_h265_profile(sdp, "1"));
+ }
+
+ // Test srs_sdp_has_h265_profile with SDP containing audio only
+ if (true) {
+ SrsSdp sdp;
+ SrsMediaDesc audio_desc("audio");
+
+ SrsMediaPayloadType opus_payload(111);
+ opus_payload.encoding_name_ = "opus";
+ audio_desc.payload_types_.push_back(opus_payload);
+
+ sdp.media_descs_.push_back(audio_desc);
+
+ // Should not find any H.265 profile in audio-only SDP
+ EXPECT_FALSE(srs_sdp_has_h265_profile(sdp, "1"));
+ }
+}
+
+VOID TEST(KernelRTCTest, H265VideoPayload)
+{
+ srs_error_t err;
+
+ // Test SrsVideoPayload::set_h265_param_desc with valid parameters
+ if (true) {
+ SrsVideoPayload payload;
+ string fmtp = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST";
+
+ HELPER_EXPECT_SUCCESS(payload.set_h265_param_desc(fmtp));
+ EXPECT_STREQ("180", payload.h265_param_.level_id.c_str());
+ EXPECT_STREQ("1", payload.h265_param_.profile_id.c_str());
+ EXPECT_STREQ("0", payload.h265_param_.tier_flag.c_str());
+ EXPECT_STREQ("SRST", payload.h265_param_.tx_mode.c_str());
+ }
+
+ // Test SrsVideoPayload::set_h265_param_desc with different order
+ if (true) {
+ SrsVideoPayload payload;
+ string fmtp = "tx-mode=MCTS;tier-flag=1;profile-id=2;level-id=93";
+
+ HELPER_EXPECT_SUCCESS(payload.set_h265_param_desc(fmtp));
+ EXPECT_STREQ("93", payload.h265_param_.level_id.c_str());
+ EXPECT_STREQ("2", payload.h265_param_.profile_id.c_str());
+ EXPECT_STREQ("1", payload.h265_param_.tier_flag.c_str());
+ EXPECT_STREQ("MCTS", payload.h265_param_.tx_mode.c_str());
+ }
+
+ // Test SrsVideoPayload::set_h265_param_desc with invalid parameter format
+ if (true) {
+ SrsVideoPayload payload;
+ string fmtp = "level-id=180;invalid-format;profile-id=1";
+
+ HELPER_EXPECT_FAILED(payload.set_h265_param_desc(fmtp));
+ }
+
+ // Test SrsVideoPayload::set_h265_param_desc with unknown parameter
+ if (true) {
+ SrsVideoPayload payload;
+ string fmtp = "level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST;unknown-param=value";
+
+ HELPER_EXPECT_FAILED(payload.set_h265_param_desc(fmtp));
+ }
+
+ // Test SrsVideoPayload::generate_media_payload_type_h265
+ if (true) {
+ SrsVideoPayload payload;
+ payload.pt_ = 96;
+ payload.name_ = "H265";
+ payload.sample_ = 90000;
+ payload.h265_param_.level_id = "180";
+ payload.h265_param_.profile_id = "1";
+ payload.h265_param_.tier_flag = "0";
+ payload.h265_param_.tx_mode = "SRST";
+
+ SrsMediaPayloadType media_type = payload.generate_media_payload_type_h265();
+ EXPECT_EQ(96, media_type.payload_type_);
+ EXPECT_STREQ("H265", media_type.encoding_name_.c_str());
+ EXPECT_EQ(90000, media_type.clock_rate_);
+ EXPECT_STREQ("level-id=180;profile-id=1;tier-flag=0;tx-mode=SRST", media_type.format_specific_param_.c_str());
+ }
+
+ // Test SrsVideoPayload::generate_media_payload_type_h265 with partial parameters
+ if (true) {
+ SrsVideoPayload payload;
+ payload.pt_ = 97;
+ payload.name_ = "H265";
+ payload.sample_ = 90000;
+ payload.h265_param_.level_id = "93";
+ payload.h265_param_.profile_id = "2";
+ // tier_flag and tx_mode are empty
+
+ SrsMediaPayloadType media_type = payload.generate_media_payload_type_h265();
+ EXPECT_EQ(97, media_type.payload_type_);
+ EXPECT_STREQ("H265", media_type.encoding_name_.c_str());
+ EXPECT_EQ(90000, media_type.clock_rate_);
+ EXPECT_STREQ("level-id=93;profile-id=2", media_type.format_specific_param_.c_str());
+ }
+
+ // Test SrsVideoPayload::copy includes H.265 parameters
+ if (true) {
+ SrsVideoPayload original;
+ original.pt_ = 96;
+ original.name_ = "H265";
+ original.sample_ = 90000;
+ original.h265_param_.level_id = "180";
+ original.h265_param_.profile_id = "1";
+ original.h265_param_.tier_flag = "0";
+ original.h265_param_.tx_mode = "SRST";
+
+ SrsVideoPayload* copied = original.copy();
+ SrsUniquePtr copied_uptr(copied);
+
+ EXPECT_EQ(original.pt_, copied->pt_);
+ EXPECT_STREQ(original.name_.c_str(), copied->name_.c_str());
+ EXPECT_EQ(original.sample_, copied->sample_);
+ EXPECT_STREQ(original.h265_param_.level_id.c_str(), copied->h265_param_.level_id.c_str());
+ EXPECT_STREQ(original.h265_param_.profile_id.c_str(), copied->h265_param_.profile_id.c_str());
+ EXPECT_STREQ(original.h265_param_.tier_flag.c_str(), copied->h265_param_.tier_flag.c_str());
+ EXPECT_STREQ(original.h265_param_.tx_mode.c_str(), copied->h265_param_.tx_mode.c_str());
+ }
+}
+
+VOID TEST(KernelRTCTest, H265RtpSTAPPayload)
+{
+ srs_error_t err;
+
+ // Test SrsRtpSTAPPayloadHevc encoding and decoding
+ if (true) {
+ SrsRtpSTAPPayloadHevc stap;
+
+ // Create sample VPS NALU
+ SrsSample* vps = new SrsSample();
+ uint8_t vps_data[] = {0x40, 0x01, 0x0c, 0x01, 0xff, 0xff, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3d, 0x95, 0x98, 0x09};
+ vps->bytes = (char*)vps_data;
+ vps->size = sizeof(vps_data);
+ stap.nalus.push_back(vps);
+
+ // Create sample SPS NALU
+ SrsSample* sps = new SrsSample();
+ uint8_t sps_data[] = {0x42, 0x01, 0x01, 0x01, 0x60, 0x00, 0x00, 0x03, 0x00, 0x90, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0x00, 0x3d, 0xa0, 0x02, 0x80, 0x80, 0x2d, 0x16, 0x59, 0x59, 0xa4, 0x93, 0x2b, 0xc0, 0x5a, 0x70, 0x80, 0x80, 0x80, 0x82};
+ sps->bytes = (char*)sps_data;
+ sps->size = sizeof(sps_data);
+ stap.nalus.push_back(sps);
+
+ // Create sample PPS NALU
+ SrsSample* pps = new SrsSample();
+ uint8_t pps_data[] = {0x44, 0x01, 0xc1, 0x72, 0xb4, 0x62, 0x40};
+ pps->bytes = (char*)pps_data;
+ pps->size = sizeof(pps_data);
+ stap.nalus.push_back(pps);
+
+ // Test encoding
+ char buf[1500];
+ SrsBuffer encode_buf(buf, sizeof(buf));
+ HELPER_EXPECT_SUCCESS(stap.encode(&encode_buf));
+
+ // Verify encoded size
+ uint64_t expected_size = 2 + 2 + sizeof(vps_data) + 2 + sizeof(sps_data) + 2 + sizeof(pps_data);
+ EXPECT_EQ(expected_size, stap.nb_bytes());
+ EXPECT_EQ((int)expected_size, encode_buf.pos());
+
+ // Test decoding
+ SrsRtpSTAPPayloadHevc decode_stap;
+ SrsBuffer decode_buf(buf, encode_buf.pos()); // Create new buffer with encoded data
+ HELPER_EXPECT_SUCCESS(decode_stap.decode(&decode_buf));
+
+ // Verify decoded NALUs
+ EXPECT_EQ(3, (int)decode_stap.nalus.size());
+
+ // Check VPS
+ SrsSample* decoded_vps = decode_stap.get_vps();
+ EXPECT_TRUE(decoded_vps != NULL);
+ EXPECT_EQ(sizeof(vps_data), (size_t)decoded_vps->size);
+
+ // Check SPS
+ SrsSample* decoded_sps = decode_stap.get_sps();
+ EXPECT_TRUE(decoded_sps != NULL);
+ EXPECT_EQ(sizeof(sps_data), (size_t)decoded_sps->size);
+
+ // Check PPS
+ SrsSample* decoded_pps = decode_stap.get_pps();
+ EXPECT_TRUE(decoded_pps != NULL);
+ EXPECT_EQ(sizeof(pps_data), (size_t)decoded_pps->size);
+
+ // Test copy functionality
+ ISrsRtpPayloader* copied = stap.copy();
+ SrsUniquePtr copied_uptr(copied);
+ SrsRtpSTAPPayloadHevc* copied_stap = dynamic_cast(copied);
+ EXPECT_TRUE(copied_stap != NULL);
+ EXPECT_EQ(3, (int)copied_stap->nalus.size());
+ }
+
+ // Test SrsRtpSTAPPayloadHevc with empty NALUs
+ if (true) {
+ SrsRtpSTAPPayloadHevc stap;
+
+ // Test encoding with no NALUs
+ char buf[100];
+ SrsBuffer encode_buf(buf, sizeof(buf));
+ HELPER_EXPECT_SUCCESS(stap.encode(&encode_buf));
+ EXPECT_EQ(2, encode_buf.pos()); // Only STAP header
+
+ // Test get functions with no NALUs
+ EXPECT_TRUE(stap.get_vps() == NULL);
+ EXPECT_TRUE(stap.get_sps() == NULL);
+ EXPECT_TRUE(stap.get_pps() == NULL);
+ }
+
+ // Test SrsRtpSTAPPayloadHevc decoding with forbidden_zero_bit set (should fail)
+ if (true) {
+ SrsRtpSTAPPayloadHevc stap;
+
+ char buf[] = {static_cast(0x80), 0x01}; // forbidden_zero_bit = 1
+ SrsBuffer decode_buf(buf, sizeof(buf));
+ HELPER_EXPECT_FAILED(stap.decode(&decode_buf));
+ }
+}
+
+VOID TEST(KernelRTCTest, H265RtpFUAPayload)
+{
+ srs_error_t err;
+
+ // Test SrsRtpFUAPayloadHevc encoding and decoding
+ if (true) {
+ SrsRtpFUAPayloadHevc fua;
+ fua.start = true;
+ fua.end = false;
+ fua.nalu_type = SrsHevcNaluType_CODED_SLICE_IDR;
+
+ // Create sample payload data
+ SrsSample* sample = new SrsSample();
+ uint8_t payload_data[] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
+ sample->bytes = (char*)payload_data;
+ sample->size = sizeof(payload_data);
+ fua.nalus.push_back(sample);
+
+ // Test encoding
+ char buf[100];
+ SrsBuffer encode_buf(buf, sizeof(buf));
+ HELPER_EXPECT_SUCCESS(fua.encode(&encode_buf));
+
+ // Verify encoded size (PayloadHdr(2) + FU header(1) + payload)
+ uint64_t expected_size = 3 + sizeof(payload_data);
+ EXPECT_EQ(expected_size, fua.nb_bytes());
+ EXPECT_EQ((int)expected_size, encode_buf.pos());
+
+ // Test decoding
+ SrsRtpFUAPayloadHevc decode_fua;
+ SrsBuffer decode_buf(buf, encode_buf.pos()); // Create new buffer with encoded data
+ HELPER_EXPECT_SUCCESS(decode_fua.decode(&decode_buf));
+
+ // Verify decoded values
+ EXPECT_TRUE(decode_fua.start);
+ EXPECT_FALSE(decode_fua.end);
+ EXPECT_EQ(SrsHevcNaluType_CODED_SLICE_IDR, decode_fua.nalu_type);
+ EXPECT_EQ(1, (int)decode_fua.nalus.size());
+ EXPECT_EQ(sizeof(payload_data), (size_t)decode_fua.nalus[0]->size);
+
+ // Test copy functionality
+ ISrsRtpPayloader* copied = fua.copy();
+ SrsUniquePtr copied_uptr(copied);
+ SrsRtpFUAPayloadHevc* copied_fua = dynamic_cast(copied);
+ EXPECT_TRUE(copied_fua != NULL);
+ EXPECT_TRUE(copied_fua->start);
+ EXPECT_FALSE(copied_fua->end);
+ EXPECT_EQ(SrsHevcNaluType_CODED_SLICE_IDR, copied_fua->nalu_type);
+ EXPECT_EQ(1, (int)copied_fua->nalus.size());
+ }
+
+ // Test SrsRtpFUAPayloadHevc2 encoding and decoding
+ if (true) {
+ SrsRtpFUAPayloadHevc2 fua2;
+ fua2.start = false;
+ fua2.end = true;
+ fua2.nalu_type = SrsHevcNaluType_CODED_SLICE_TRAIL_R;
+
+ uint8_t payload_data[] = {0xAA, 0xBB, 0xCC, 0xDD};
+ fua2.payload = (char*)payload_data;
+ fua2.size = sizeof(payload_data);
+
+ // Test encoding
+ char buf[100];
+ SrsBuffer encode_buf(buf, sizeof(buf));
+ HELPER_EXPECT_SUCCESS(fua2.encode(&encode_buf));
+
+ // Verify encoded size (PayloadHdr(2) + FU header(1) + payload)
+ uint64_t expected_size = 3 + sizeof(payload_data);
+ EXPECT_EQ(expected_size, fua2.nb_bytes());
+ EXPECT_EQ((int)expected_size, encode_buf.pos());
+
+ // Test decoding
+ SrsRtpFUAPayloadHevc2 decode_fua2;
+ SrsBuffer decode_buf2(buf, encode_buf.pos()); // Create new buffer with encoded data
+ HELPER_EXPECT_SUCCESS(decode_fua2.decode(&decode_buf2));
+
+ // Verify decoded values
+ EXPECT_FALSE(decode_fua2.start);
+ EXPECT_TRUE(decode_fua2.end);
+ EXPECT_EQ(SrsHevcNaluType_CODED_SLICE_TRAIL_R, decode_fua2.nalu_type);
+ EXPECT_EQ(sizeof(payload_data), (size_t)decode_fua2.size);
+
+ // Test copy functionality
+ ISrsRtpPayloader* copied = fua2.copy();
+ SrsUniquePtr copied_uptr(copied);
+ SrsRtpFUAPayloadHevc2* copied_fua2 = dynamic_cast(copied);
+ EXPECT_TRUE(copied_fua2 != NULL);
+ EXPECT_FALSE(copied_fua2->start);
+ EXPECT_TRUE(copied_fua2->end);
+ EXPECT_EQ(SrsHevcNaluType_CODED_SLICE_TRAIL_R, copied_fua2->nalu_type);
+ EXPECT_EQ(sizeof(payload_data), (size_t)copied_fua2->size);
+ }
+}
+
+VOID TEST(KernelRTCTest, H265RtpPacketKeyframe)
+{
+ // Test RTP packet keyframe detection for HEVC
+ if (true) {
+ SrsRtpPacket pkt;
+ pkt.frame_type = SrsFrameTypeVideo;
+
+ // Test VPS NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_VPS;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test SPS NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_SPS;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test PPS NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_PPS;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test IDR NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_CODED_SLICE_IDR;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test CRA NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_CODED_SLICE_CRA;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test BLA NALU (should be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_CODED_SLICE_BLA;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test regular P-frame NALU (should not be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_CODED_SLICE_TRAIL_R;
+ EXPECT_FALSE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test regular B-frame NALU (should not be keyframe)
+ pkt.nalu_type = SrsHevcNaluType_CODED_SLICE_TSA_N;
+ EXPECT_FALSE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+ }
+
+ // Test HEVC STAP payload keyframe detection
+ if (true) {
+ SrsRtpPacket pkt;
+ pkt.frame_type = SrsFrameTypeVideo;
+ pkt.nalu_type = kStapHevc;
+
+ SrsRtpSTAPPayloadHevc* stap_payload = new SrsRtpSTAPPayloadHevc();
+ pkt.set_payload(stap_payload, SrsRtpPacketPayloadTypeSTAPHevc);
+
+ // Create VPS NALU
+ SrsSample* vps = new SrsSample();
+ uint8_t vps_data[] = {0x40, 0x01}; // VPS NALU header
+ vps->bytes = (char*)vps_data;
+ vps->size = sizeof(vps_data);
+ stap_payload->nalus.push_back(vps);
+
+ // Should be keyframe because it contains VPS
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+ }
+
+ // Test HEVC FU-A payload keyframe detection
+ if (true) {
+ SrsRtpPacket pkt;
+ pkt.frame_type = SrsFrameTypeVideo;
+ pkt.nalu_type = kFuHevc;
+
+ SrsRtpFUAPayloadHevc2* fua_payload = new SrsRtpFUAPayloadHevc2();
+ pkt.set_payload(fua_payload, SrsRtpPacketPayloadTypeFUAHevc2);
+
+ // Test IDR slice in FU-A (should be keyframe)
+ fua_payload->nalu_type = SrsHevcNaluType_CODED_SLICE_IDR;
+ EXPECT_TRUE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+
+ // Test regular slice in FU-A (should not be keyframe)
+ fua_payload->nalu_type = SrsHevcNaluType_CODED_SLICE_TRAIL_R;
+ EXPECT_FALSE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+ }
+
+ // Test audio packet (should not be keyframe regardless of NALU type)
+ if (true) {
+ SrsRtpPacket pkt;
+ pkt.frame_type = SrsFrameTypeAudio;
+ pkt.nalu_type = SrsHevcNaluType_VPS;
+ EXPECT_FALSE(pkt.is_keyframe(SrsVideoCodecIdHEVC));
+ }
+}
+
+// Note: Stream bridge codec switching tests are complex and require full RTC infrastructure
+// These would be better tested in integration tests rather than unit tests
+VOID TEST(KernelRTCTest, H265RtpRawNALUsSkipBytes)
+{
+ srs_error_t err;
+
+ // Test SrsRtpRawNALUs::skip_bytes for HEVC (2 bytes header)
+ if (true) {
+ SrsRtpRawNALUs raw_nalus;
+
+ // Create sample HEVC NALU
+ SrsSample* sample = new SrsSample();
+ uint8_t nalu_data[] = {0x26, 0x01, 0x12, 0x34, 0x56, 0x78}; // IDR slice
+ sample->bytes = (char*)nalu_data;
+ sample->size = sizeof(nalu_data);
+ raw_nalus.push_back(sample);
+
+ // Skip HEVC header (2 bytes)
+ uint8_t header = raw_nalus.skip_bytes(SrsHevcNaluHeaderSize);
+ EXPECT_EQ(0x26, header); // Should return first byte
+
+ // Verify remaining data
+ std::vector samples;
+ HELPER_EXPECT_SUCCESS(raw_nalus.read_samples(samples, 4));
+ EXPECT_EQ(1, (int)samples.size());
+ EXPECT_EQ(4, samples[0]->size);
+ EXPECT_EQ(0x12, (uint8_t)samples[0]->bytes[0]);
+ EXPECT_EQ(0x34, (uint8_t)samples[0]->bytes[1]);
+ EXPECT_EQ(0x56, (uint8_t)samples[0]->bytes[2]);
+ EXPECT_EQ(0x78, (uint8_t)samples[0]->bytes[3]);
+
+ // Clean up
+ for (size_t i = 0; i < samples.size(); i++) {
+ srs_freep(samples[i]);
+ }
+ }
+
+ // Test SrsRtpRawNALUs::skip_bytes for H.264 (1 byte header)
+ if (true) {
+ SrsRtpRawNALUs raw_nalus;
+
+ // Create sample H.264 NALU
+ SrsSample* sample = new SrsSample();
+ uint8_t nalu_data[] = {0x65, 0x12, 0x34, 0x56}; // IDR slice
+ sample->bytes = (char*)nalu_data;
+ sample->size = sizeof(nalu_data);
+ raw_nalus.push_back(sample);
+
+ // Skip H.264 header (1 byte)
+ uint8_t header = raw_nalus.skip_bytes(SrsAvcNaluHeaderSize);
+ EXPECT_EQ(0x65, header); // Should return first byte
+
+ // Verify remaining data
+ std::vector samples;
+ HELPER_EXPECT_SUCCESS(raw_nalus.read_samples(samples, 3));
+ EXPECT_EQ(1, (int)samples.size());
+ EXPECT_EQ(3, samples[0]->size);
+ EXPECT_EQ(0x12, (uint8_t)samples[0]->bytes[0]);
+ EXPECT_EQ(0x34, (uint8_t)samples[0]->bytes[1]);
+ EXPECT_EQ(0x56, (uint8_t)samples[0]->bytes[2]);
+
+ // Clean up
+ for (size_t i = 0; i < samples.size(); i++) {
+ srs_freep(samples[i]);
+ }
+ }
+}
+