summaryrefslogtreecommitdiff
path: root/vendor/github.com/pion/rtcp
diff options
context:
space:
mode:
authorkali kaneko (leap communications) <kali@leap.se>2021-11-29 01:46:27 +0100
committerkali kaneko (leap communications) <kali@leap.se>2021-11-29 18:14:16 +0100
commit18f52af5be3a9a0c73811706108f790d65ee9c67 (patch)
treee13cbacb47d56919caa9c44a2b45dec1497a7860 /vendor/github.com/pion/rtcp
parentebcef0d57b6ecb5a40c6579f6be07182dd3033ba (diff)
[pkg] update vendor
Diffstat (limited to 'vendor/github.com/pion/rtcp')
-rw-r--r--vendor/github.com/pion/rtcp/.gitignore24
-rw-r--r--vendor/github.com/pion/rtcp/.golangci.yml89
-rw-r--r--vendor/github.com/pion/rtcp/LICENSE21
-rw-r--r--vendor/github.com/pion/rtcp/README.md49
-rw-r--r--vendor/github.com/pion/rtcp/codecov.yml20
-rw-r--r--vendor/github.com/pion/rtcp/compound_packet.go136
-rw-r--r--vendor/github.com/pion/rtcp/doc.go39
-rw-r--r--vendor/github.com/pion/rtcp/errors.go30
-rw-r--r--vendor/github.com/pion/rtcp/full_intra_request.go107
-rw-r--r--vendor/github.com/pion/rtcp/fuzz.go51
-rw-r--r--vendor/github.com/pion/rtcp/go.mod5
-rw-r--r--vendor/github.com/pion/rtcp/go.sum11
-rw-r--r--vendor/github.com/pion/rtcp/goodbye.go146
-rw-r--r--vendor/github.com/pion/rtcp/header.go140
-rw-r--r--vendor/github.com/pion/rtcp/packet.go115
-rw-r--r--vendor/github.com/pion/rtcp/picture_loss_indication.go91
-rw-r--r--vendor/github.com/pion/rtcp/rapid_resynchronization_request.go88
-rw-r--r--vendor/github.com/pion/rtcp/raw_packet.go44
-rw-r--r--vendor/github.com/pion/rtcp/receiver_estimated_maximum_bitrate.go284
-rw-r--r--vendor/github.com/pion/rtcp/receiver_report.go193
-rw-r--r--vendor/github.com/pion/rtcp/reception_report.go130
-rw-r--r--vendor/github.com/pion/rtcp/renovate.json15
-rw-r--r--vendor/github.com/pion/rtcp/sender_report.go260
-rw-r--r--vendor/github.com/pion/rtcp/slice_loss_indication.go115
-rw-r--r--vendor/github.com/pion/rtcp/source_description.go352
-rw-r--r--vendor/github.com/pion/rtcp/transport_layer_cc.go560
-rw-r--r--vendor/github.com/pion/rtcp/transport_layer_nack.go174
-rw-r--r--vendor/github.com/pion/rtcp/util.go38
28 files changed, 3327 insertions, 0 deletions
diff --git a/vendor/github.com/pion/rtcp/.gitignore b/vendor/github.com/pion/rtcp/.gitignore
new file mode 100644
index 0000000..83db74b
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/.gitignore
@@ -0,0 +1,24 @@
+### JetBrains IDE ###
+#####################
+.idea/
+
+### Emacs Temporary Files ###
+#############################
+*~
+
+### Folders ###
+###############
+bin/
+vendor/
+node_modules/
+
+### Files ###
+#############
+*.ivf
+*.ogg
+tags
+cover.out
+*.sw[poe]
+*.wasm
+examples/sfu-ws/cert.pem
+examples/sfu-ws/key.pem
diff --git a/vendor/github.com/pion/rtcp/.golangci.yml b/vendor/github.com/pion/rtcp/.golangci.yml
new file mode 100644
index 0000000..d6162c9
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/.golangci.yml
@@ -0,0 +1,89 @@
+linters-settings:
+ govet:
+ check-shadowing: true
+ misspell:
+ locale: US
+ exhaustive:
+ default-signifies-exhaustive: true
+ gomodguard:
+ blocked:
+ modules:
+ - github.com/pkg/errors:
+ recommendations:
+ - errors
+
+linters:
+ enable:
+ - asciicheck # Simple linter to check that your code does not contain non-ASCII identifiers
+ - bodyclose # checks whether HTTP response body is closed successfully
+ - deadcode # Finds unused code
+ - depguard # Go linter that checks if package imports are in a list of acceptable packages
+ - dogsled # Checks assignments with too many blank identifiers (e.g. x, _, _, _, := f())
+ - dupl # Tool for code clone detection
+ - errcheck # Errcheck is a program for checking for unchecked errors in go programs. These unchecked errors can be critical bugs in some cases
+ - exhaustive # check exhaustiveness of enum switch statements
+ - exportloopref # checks for pointers to enclosing loop variables
+ - 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
+ - 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
+ - golint # Golint differs from gofmt. Gofmt reformats Go source code, whereas golint prints out style mistakes
+ - 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
+ - govet # Vet examines Go source code and reports suspicious constructs, such as Printf calls whose arguments do not align with the format string
+ - ineffassign # Detects when assignments to existing variables are not used
+ - misspell # Finds commonly misspelled English words in comments
+ - nakedret # Finds naked returns in functions greater than a specified function length
+ - noctx # noctx finds sending http request without context.Context
+ - scopelint # Scopelint checks for unpinned variables in go programs
+ - staticcheck # Staticcheck is a go vet on steroids, applying a ton of static analysis checks
+ - structcheck # Finds unused struct fields
+ - stylecheck # Stylecheck is a replacement for golint
+ - 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
+ - varcheck # Finds unused global variables and constants
+ - whitespace # Tool for detection of leading and trailing whitespace
+ disable:
+ - 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.
+ - lll # Reports long lines
+ - maligned # Tool to detect Go structs that would take less memory if their fields were sorted
+ - nestif # Reports deeply nested if statements
+ - nlreturn # nlreturn checks for a new line before return and branch statements to increase code clarity
+ - nolintlint # Reports ill-formed or insufficient nolint directives
+ - prealloc # Finds slice declarations that could potentially be preallocated
+ - 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
+ - wsl # Whitespace Linter - Forces you to use empty lines!
+
+issues:
+ exclude-use-default: false
+ exclude-rules:
+ # Allow complex tests, better to be self contained
+ - path: _test\.go
+ linters:
+ - gocognit
+
+ # Allow complex main function in examples
+ - path: examples
+ text: "of func `main` is high"
+ linters:
+ - gocognit
+
+run:
+ skip-dirs-use-default: false
diff --git a/vendor/github.com/pion/rtcp/LICENSE b/vendor/github.com/pion/rtcp/LICENSE
new file mode 100644
index 0000000..ab60297
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/pion/rtcp/README.md b/vendor/github.com/pion/rtcp/README.md
new file mode 100644
index 0000000..a054dae
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/README.md
@@ -0,0 +1,49 @@
+<h1 align="center">
+ <br>
+ Pion RTCP
+ <br>
+</h1>
+<h4 align="center">A Go implementation of RTCP</h4>
+<p align="center">
+ <a href="https://pion.ly"><img src="https://img.shields.io/badge/pion-rtcp-gray.svg?longCache=true&colorB=brightgreen" alt="Pion RTCP"></a>
+ <a href="https://sourcegraph.com/github.com/pion/rtcp?badge"><img src="https://sourcegraph.com/github.com/pion/rtcp/-/badge.svg" alt="Sourcegraph Widget"></a>
+ <a href="https://pion.ly/slack"><img src="https://img.shields.io/badge/join-us%20on%20slack-gray.svg?longCache=true&logo=slack&colorB=brightgreen" alt="Slack Widget"></a>
+ <br>
+ <a href="https://travis-ci.org/pion/rtcp"><img src="https://travis-ci.org/pion/rtcp.svg?branch=master" alt="Build Status"></a>
+ <a href="https://pkg.go.dev/github.com/pion/rtcp"><img src="https://godoc.org/github.com/pion/rtcp?status.svg" alt="GoDoc"></a>
+ <a href="https://codecov.io/gh/pion/rtcp"><img src="https://codecov.io/gh/pion/rtcp/branch/master/graph/badge.svg" alt="Coverage Status"></a>
+ <a href="https://goreportcard.com/report/github.com/pion/rtcp"><img src="https://goreportcard.com/badge/github.com/pion/rtcp" alt="Go Report Card"></a>
+ <a href="LICENSE"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a>
+</p>
+<br>
+
+See [DESIGN.md](DESIGN.md) for an overview of features and future goals.
+
+### Roadmap
+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 [Golang Slack](https://invite.slack.golangbridge.org/). Sign up and join the **#pion** channel for discussions and support. You can also use [Pion mailing list](https://groups.google.com/forum/#!forum/pion).
+
+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)
+
+### Contributing
+Check out the **[contributing wiki](https://github.com/pion/webrtc/wiki/Contributing)** to join the group of amazing people making this project possible:
+
+* [Max Hawkins](https://github.com/maxhawkins) - *Original Author*
+* [Woodrow Douglass](https://github.com/wdouglass) *RTCP, RTP improvements, G.722 support, Bugfixes*
+* [Sean DuBois](https://github.com/Sean-Der) - *Linter fixes*
+* [adwpc](https://github.com/adwpc)
+* [Luke Curley](https://github.com/kixelated)
+* [Hugo Arregui](https://github.com/hugoArregui)
+* [Atsushi Watanabe](https://github.com/at-wat)
+* [Juliusz Chroboczek](https://github.com/jech)
+* [Gabor Pongracz](https://github.com/pongraczgabor87)
+* [Simone Gotti](https://github.com/sgotti)
+* [lllf](https://github.com/LittleLightLittleFire)
+* [cnderrauber](https://github.com/cnderrauber)
+
+### License
+MIT License - see [LICENSE](LICENSE) for full text
diff --git a/vendor/github.com/pion/rtcp/codecov.yml b/vendor/github.com/pion/rtcp/codecov.yml
new file mode 100644
index 0000000..085200a
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/codecov.yml
@@ -0,0 +1,20 @@
+#
+# DO NOT EDIT THIS FILE
+#
+# It is automatically copied from https://github.com/pion/.goassets repository.
+#
+
+coverage:
+ status:
+ project:
+ default:
+ # Allow decreasing 2% of total coverage to avoid noise.
+ threshold: 2%
+ patch:
+ default:
+ target: 70%
+ only_pulls: true
+
+ignore:
+ - "examples/*"
+ - "examples/**/*"
diff --git a/vendor/github.com/pion/rtcp/compound_packet.go b/vendor/github.com/pion/rtcp/compound_packet.go
new file mode 100644
index 0000000..2c74279
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/compound_packet.go
@@ -0,0 +1,136 @@
+package rtcp
+
+// A CompoundPacket is a collection of RTCP packets transmitted as a single packet with
+// the underlying protocol (for example UDP).
+//
+// To maximize the resolution of receiption statistics, the first Packet in a CompoundPacket
+// must always be either a SenderReport or a ReceiverReport. This is true even if no data
+// has been sent or received, in which case an empty ReceiverReport must be sent, and even
+// if the only other RTCP packet in the compound packet is a Goodbye.
+//
+// Next, a SourceDescription containing a CNAME item must be included in each CompoundPacket
+// to identify the source and to begin associating media for purposes such as lip-sync.
+//
+// Other RTCP packet types may follow in any order. Packet types may appear more than once.
+type CompoundPacket []Packet
+
+var _ Packet = (*CompoundPacket)(nil) // assert is a Packet
+
+// Validate returns an error if this is not an RFC-compliant CompoundPacket.
+func (c CompoundPacket) Validate() error {
+ if len(c) == 0 {
+ return errEmptyCompound
+ }
+
+ // SenderReport and ReceiverReport are the only types that
+ // are allowed to be the first packet in a compound datagram
+ switch c[0].(type) {
+ case *SenderReport, *ReceiverReport:
+ // ok
+ default:
+ return errBadFirstPacket
+ }
+
+ for _, pkt := range c[1:] {
+ switch p := pkt.(type) {
+ // If the number of RecetpionReports exceeds 31 additional ReceiverReports
+ // can be included here.
+ case *ReceiverReport:
+ continue
+
+ // A SourceDescription containing a CNAME must be included in every
+ // CompoundPacket.
+ case *SourceDescription:
+ var hasCNAME bool
+ for _, c := range p.Chunks {
+ for _, it := range c.Items {
+ if it.Type == SDESCNAME {
+ hasCNAME = true
+ }
+ }
+ }
+
+ if !hasCNAME {
+ return errMissingCNAME
+ }
+
+ return nil
+
+ // Other packets are not permitted before the CNAME
+ default:
+ return errPacketBeforeCNAME
+ }
+ }
+
+ // CNAME never reached
+ return errMissingCNAME
+}
+
+// CNAME returns the CNAME that *must* be present in every CompoundPacket
+func (c CompoundPacket) CNAME() (string, error) {
+ var err error
+
+ if len(c) < 1 {
+ return "", errEmptyCompound
+ }
+
+ for _, pkt := range c[1:] {
+ sdes, ok := pkt.(*SourceDescription)
+ if ok {
+ for _, c := range sdes.Chunks {
+ for _, it := range c.Items {
+ if it.Type == SDESCNAME {
+ return it.Text, err
+ }
+ }
+ }
+ } else {
+ _, ok := pkt.(*ReceiverReport)
+ if !ok {
+ err = errPacketBeforeCNAME
+ }
+ }
+ }
+ return "", errMissingCNAME
+}
+
+// Marshal encodes the CompoundPacket as binary.
+func (c CompoundPacket) Marshal() ([]byte, error) {
+ if err := c.Validate(); err != nil {
+ return nil, err
+ }
+
+ p := []Packet(c)
+ return Marshal(p)
+}
+
+// Unmarshal decodes a CompoundPacket from binary.
+func (c *CompoundPacket) Unmarshal(rawData []byte) error {
+ out := make(CompoundPacket, 0)
+ for len(rawData) != 0 {
+ p, processed, err := unmarshal(rawData)
+ if err != nil {
+ return err
+ }
+
+ out = append(out, p)
+ rawData = rawData[processed:]
+ }
+ *c = out
+
+ if err := c.Validate(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// DestinationSSRC returns the synchronization sources associated with this
+// CompoundPacket's reception report.
+func (c CompoundPacket) DestinationSSRC() []uint32 {
+ if len(c) == 0 {
+ return nil
+ }
+
+ return c[0].DestinationSSRC()
+}
diff --git a/vendor/github.com/pion/rtcp/doc.go b/vendor/github.com/pion/rtcp/doc.go
new file mode 100644
index 0000000..fa948df
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/doc.go
@@ -0,0 +1,39 @@
+/*
+Package rtcp implements encoding and decoding of RTCP packets according to RFCs 3550 and 5506.
+
+RTCP is a sister protocol of the Real-time Transport Protocol (RTP). Its basic functionality
+and packet structure is defined in RFC 3550. RTCP provides out-of-band statistics and control
+information for an RTP session. It partners with RTP in the delivery and packaging of multimedia data,
+but does not transport any media data itself.
+
+The primary function of RTCP is to provide feedback on the quality of service (QoS)
+in media distribution by periodically sending statistics information such as transmitted octet
+and packet counts, packet loss, packet delay variation, and round-trip delay time to participants
+in a streaming multimedia session. An application may use this information to control quality of
+service parameters, perhaps by limiting flow, or using a different codec.
+
+Decoding RTCP packets:
+
+ pkt, err := rtcp.Unmarshal(rtcpData)
+ // ...
+
+ switch p := pkt.(type) {
+ case *rtcp.CompoundPacket:
+ ...
+ case *rtcp.PictureLossIndication:
+ ...
+ default:
+ ...
+ }
+
+Encoding RTCP packets:
+
+ pkt := &rtcp.PictureLossIndication{
+ SenderSSRC: senderSSRC,
+ MediaSSRC: mediaSSRC
+ }
+ pliData, err := pkt.Marshal()
+ // ...
+
+*/
+package rtcp
diff --git a/vendor/github.com/pion/rtcp/errors.go b/vendor/github.com/pion/rtcp/errors.go
new file mode 100644
index 0000000..d1b00c5
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/errors.go
@@ -0,0 +1,30 @@
+package rtcp
+
+import "errors"
+
+var (
+ errWrongMarshalSize = errors.New("rtcp: wrong marshal size")
+ errInvalidTotalLost = errors.New("rtcp: invalid total lost count")
+ errInvalidHeader = errors.New("rtcp: invalid header")
+ errEmptyCompound = errors.New("rtcp: empty compound packet")
+ errBadFirstPacket = errors.New("rtcp: first packet in compound must be SR or RR")
+ errMissingCNAME = errors.New("rtcp: compound missing SourceDescription with CNAME")
+ errPacketBeforeCNAME = errors.New("rtcp: feedback packet seen before CNAME")
+ errTooManyReports = errors.New("rtcp: too many reports")
+ errTooManyChunks = errors.New("rtcp: too many chunks")
+ errTooManySources = errors.New("rtcp: too many sources")
+ errPacketTooShort = errors.New("rtcp: packet too short")
+ errWrongType = errors.New("rtcp: wrong packet type")
+ errSDESTextTooLong = errors.New("rtcp: sdes must be < 255 octets long")
+ errSDESMissingType = errors.New("rtcp: sdes item missing type")
+ errReasonTooLong = errors.New("rtcp: reason must be < 255 octets long")
+ errBadVersion = errors.New("rtcp: invalid packet version")
+ errWrongPadding = errors.New("rtcp: invalid padding value")
+ errWrongFeedbackType = errors.New("rtcp: wrong feedback message type")
+ errWrongPayloadType = errors.New("rtcp: wrong payload type")
+ errHeaderTooSmall = errors.New("rtcp: header length is too small")
+ errSSRCMustBeZero = errors.New("rtcp: media SSRC must be 0")
+ errMissingREMBidentifier = errors.New("missing REMB identifier")
+ errSSRCNumAndLengthMismatch = errors.New("SSRC num and length do not match")
+ errInvalidSizeOrStartIndex = errors.New("invalid size or startIndex")
+)
diff --git a/vendor/github.com/pion/rtcp/full_intra_request.go b/vendor/github.com/pion/rtcp/full_intra_request.go
new file mode 100644
index 0000000..74ca928
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/full_intra_request.go
@@ -0,0 +1,107 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// A FIREntry is a (SSRC, seqno) pair, as carried by FullIntraRequest.
+type FIREntry struct {
+ SSRC uint32
+ SequenceNumber uint8
+}
+
+// The FullIntraRequest packet is used to reliably request an Intra frame
+// in a video stream. See RFC 5104 Section 3.5.1. This is not for loss
+// recovery, which should use PictureLossIndication (PLI) instead.
+type FullIntraRequest struct {
+ SenderSSRC uint32
+ MediaSSRC uint32
+
+ FIR []FIREntry
+}
+
+const (
+ firOffset = 8
+)
+
+var _ Packet = (*FullIntraRequest)(nil)
+
+// Marshal encodes the FullIntraRequest
+func (p FullIntraRequest) Marshal() ([]byte, error) {
+ rawPacket := make([]byte, firOffset+(len(p.FIR)*8))
+ binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
+ binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
+ for i, fir := range p.FIR {
+ binary.BigEndian.PutUint32(rawPacket[firOffset+8*i:], fir.SSRC)
+ rawPacket[firOffset+8*i+4] = fir.SequenceNumber
+ }
+ h := p.Header()
+ hData, err := h.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ return append(hData, rawPacket...), nil
+}
+
+// Unmarshal decodes the TransportLayerNack
+func (p *FullIntraRequest) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < (headerLength + ssrcLength) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if len(rawPacket) < (headerLength + int(4*h.Length)) {
+ return errPacketTooShort
+ }
+
+ if h.Type != TypePayloadSpecificFeedback || h.Count != FormatFIR {
+ return errWrongType
+ }
+
+ p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ for i := headerLength + firOffset; i < (headerLength + int(h.Length*4)); i += 8 {
+ p.FIR = append(p.FIR, FIREntry{
+ binary.BigEndian.Uint32(rawPacket[i:]),
+ rawPacket[i+4],
+ })
+ }
+ return nil
+}
+
+// Header returns the Header associated with this packet.
+func (p *FullIntraRequest) Header() Header {
+ return Header{
+ Count: FormatFIR,
+ Type: TypePayloadSpecificFeedback,
+ Length: uint16((p.len() / 4) - 1),
+ }
+}
+
+func (p *FullIntraRequest) len() int {
+ return headerLength + firOffset + len(p.FIR)*8
+}
+
+func (p *FullIntraRequest) String() string {
+ out := fmt.Sprintf("FullIntraRequest %x %x",
+ p.SenderSSRC, p.MediaSSRC)
+ for _, e := range p.FIR {
+ out += fmt.Sprintf(" (%x %v)", e.SSRC, e.SequenceNumber)
+ }
+ return out
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *FullIntraRequest) DestinationSSRC() []uint32 {
+ ssrcs := make([]uint32, 0, len(p.FIR))
+ for _, entry := range p.FIR {
+ ssrcs = append(ssrcs, entry.SSRC)
+ }
+ return ssrcs
+}
diff --git a/vendor/github.com/pion/rtcp/fuzz.go b/vendor/github.com/pion/rtcp/fuzz.go
new file mode 100644
index 0000000..2ea4fb1
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/fuzz.go
@@ -0,0 +1,51 @@
+// +build gofuzz
+
+package rtcp
+
+import (
+ "bytes"
+ "io"
+)
+
+// Fuzz implements a randomized fuzz test of the rtcp
+// parser using go-fuzz.
+//
+// To run the fuzzer, first download go-fuzz:
+// `go get github.com/dvyukov/go-fuzz/...`
+//
+// Then build the testing package:
+// `go-fuzz-build github.com/pion/webrtc`
+//
+// And run the fuzzer on the corpus:
+// ```
+// mkdir workdir
+//
+// # optionally add a starter corpus of valid rtcp packets.
+// # the corpus should be as compact and diverse as possible.
+// cp -r ~/my-rtcp-packets workdir/corpus
+//
+// go-fuzz -bin=ase-fuzz.zip -workdir=workdir
+// ````
+func Fuzz(data []byte) int {
+ r := NewReader(bytes.NewReader(data))
+ for {
+ _, data, err := r.ReadPacket()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return 0
+ }
+
+ packet, err := Unmarshal(data)
+ if err != nil {
+ return 0
+ }
+
+ if _, err := packet.Marshal(); err != nil {
+ return 0
+ }
+ }
+
+ return 1
+}
diff --git a/vendor/github.com/pion/rtcp/go.mod b/vendor/github.com/pion/rtcp/go.mod
new file mode 100644
index 0000000..28b6e9d
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/go.mod
@@ -0,0 +1,5 @@
+module github.com/pion/rtcp
+
+go 1.13
+
+require github.com/stretchr/testify v1.6.1
diff --git a/vendor/github.com/pion/rtcp/go.sum b/vendor/github.com/pion/rtcp/go.sum
new file mode 100644
index 0000000..afe7890
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/go.sum
@@ -0,0 +1,11 @@
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
+github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/vendor/github.com/pion/rtcp/goodbye.go b/vendor/github.com/pion/rtcp/goodbye.go
new file mode 100644
index 0000000..b8718b3
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/goodbye.go
@@ -0,0 +1,146 @@
+package rtcp
+
+import (
+ "encoding/binary"
+)
+
+// The Goodbye packet indicates that one or more sources are no longer active.
+type Goodbye struct {
+ // The SSRC/CSRC identifiers that are no longer active
+ Sources []uint32
+ // Optional text indicating the reason for leaving, e.g., "camera malfunction" or "RTP loop detected"
+ Reason string
+}
+
+var _ Packet = (*Goodbye)(nil) // assert is a Packet
+
+// Marshal encodes the Goodbye packet in binary
+func (g Goodbye) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V=2|P| SC | PT=BYE=203 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC/CSRC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * (opt) | length | reason for leaving ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ rawPacket := make([]byte, g.len())
+ packetBody := rawPacket[headerLength:]
+
+ if len(g.Sources) > countMax {
+ return nil, errTooManySources
+ }
+
+ for i, s := range g.Sources {
+ binary.BigEndian.PutUint32(packetBody[i*ssrcLength:], s)
+ }
+
+ if g.Reason != "" {
+ reason := []byte(g.Reason)
+
+ if len(reason) > sdesMaxOctetCount {
+ return nil, errReasonTooLong
+ }
+
+ reasonOffset := len(g.Sources) * ssrcLength
+ packetBody[reasonOffset] = uint8(len(reason))
+ copy(packetBody[reasonOffset+1:], reason)
+ }
+
+ hData, err := g.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the Goodbye packet from binary
+func (g *Goodbye) Unmarshal(rawPacket []byte) error {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V=2|P| SC | PT=BYE=203 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC/CSRC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * (opt) | length | reason for leaving ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ var header Header
+ if err := header.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if header.Type != TypeGoodbye {
+ return errWrongType
+ }
+
+ if getPadding(len(rawPacket)) != 0 {
+ return errPacketTooShort
+ }
+
+ g.Sources = make([]uint32, header.Count)
+
+ reasonOffset := int(headerLength + header.Count*ssrcLength)
+ if reasonOffset > len(rawPacket) {
+ return errPacketTooShort
+ }
+
+ for i := 0; i < int(header.Count); i++ {
+ offset := headerLength + i*ssrcLength
+
+ g.Sources[i] = binary.BigEndian.Uint32(rawPacket[offset:])
+ }
+
+ if reasonOffset < len(rawPacket) {
+ reasonLen := int(rawPacket[reasonOffset])
+ reasonEnd := reasonOffset + 1 + reasonLen
+
+ if reasonEnd > len(rawPacket) {
+ return errPacketTooShort
+ }
+
+ g.Reason = string(rawPacket[reasonOffset+1 : reasonEnd])
+ }
+
+ return nil
+}
+
+// Header returns the Header associated with this packet.
+func (g *Goodbye) Header() Header {
+ return Header{
+ Padding: false,
+ Count: uint8(len(g.Sources)),
+ Type: TypeGoodbye,
+ Length: uint16((g.len() / 4) - 1),
+ }
+}
+
+func (g *Goodbye) len() int {
+ srcsLength := len(g.Sources) * ssrcLength
+ reasonLength := len(g.Reason) + 1
+
+ l := headerLength + srcsLength + reasonLength
+
+ // align to 32-bit boundary
+ return l + getPadding(l)
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (g *Goodbye) DestinationSSRC() []uint32 {
+ out := make([]uint32, len(g.Sources))
+ copy(out, g.Sources)
+ return out
+}
diff --git a/vendor/github.com/pion/rtcp/header.go b/vendor/github.com/pion/rtcp/header.go
new file mode 100644
index 0000000..055ca18
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/header.go
@@ -0,0 +1,140 @@
+package rtcp
+
+import (
+ "encoding/binary"
+)
+
+// PacketType specifies the type of an RTCP packet
+type PacketType uint8
+
+// RTCP packet types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-4
+const (
+ TypeSenderReport PacketType = 200 // RFC 3550, 6.4.1
+ TypeReceiverReport PacketType = 201 // RFC 3550, 6.4.2
+ TypeSourceDescription PacketType = 202 // RFC 3550, 6.5
+ TypeGoodbye PacketType = 203 // RFC 3550, 6.6
+ TypeApplicationDefined PacketType = 204 // RFC 3550, 6.7 (unimplemented)
+ TypeTransportSpecificFeedback PacketType = 205 // RFC 4585, 6051
+ TypePayloadSpecificFeedback PacketType = 206 // RFC 4585, 6.3
+
+)
+
+// Transport and Payload specific feedback messages overload the count field to act as a message type. those are listed here
+const (
+ FormatSLI uint8 = 2
+ FormatPLI uint8 = 1
+ FormatFIR uint8 = 4
+ FormatTLN uint8 = 1
+ FormatRRR uint8 = 5
+ FormatREMB uint8 = 15
+
+ //https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
+ FormatTCC uint8 = 15
+)
+
+func (p PacketType) String() string {
+ switch p {
+ case TypeSenderReport:
+ return "SR"
+ case TypeReceiverReport:
+ return "RR"
+ case TypeSourceDescription:
+ return "SDES"
+ case TypeGoodbye:
+ return "BYE"
+ case TypeApplicationDefined:
+ return "APP"
+ case TypeTransportSpecificFeedback:
+ return "TSFB"
+ case TypePayloadSpecificFeedback:
+ return "PSFB"
+ default:
+ return string(p)
+ }
+}
+
+const rtpVersion = 2
+
+// A Header is the common header shared by all RTCP packets
+type Header struct {
+ // If the padding bit is set, this individual RTCP packet contains
+ // some additional padding octets at the end which are not part of
+ // the control information but are included in the length field.
+ Padding bool
+ // The number of reception reports, sources contained or FMT in this packet (depending on the Type)
+ Count uint8
+ // The RTCP packet type for this packet
+ Type PacketType
+ // The length of this RTCP packet in 32-bit words minus one,
+ // including the header and any padding.
+ Length uint16
+}
+
+const (
+ headerLength = 4
+ versionShift = 6
+ versionMask = 0x3
+ paddingShift = 5
+ paddingMask = 0x1
+ countShift = 0
+ countMask = 0x1f
+ countMax = (1 << 5) - 1
+)
+
+// Marshal encodes the Header in binary
+func (h Header) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V=2|P| RC | PT=SR=200 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ rawPacket := make([]byte, headerLength)
+
+ rawPacket[0] |= rtpVersion << versionShift
+
+ if h.Padding {
+ rawPacket[0] |= 1 << paddingShift
+ }
+
+ if h.Count > 31 {
+ return nil, errInvalidHeader
+ }
+ rawPacket[0] |= h.Count << countShift
+
+ rawPacket[1] = uint8(h.Type)
+
+ binary.BigEndian.PutUint16(rawPacket[2:], h.Length)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the Header from binary
+func (h *Header) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < headerLength {
+ return errPacketTooShort
+ }
+
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * |V=2|P| RC | PT | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ version := rawPacket[0] >> versionShift & versionMask
+ if version != rtpVersion {
+ return errBadVersion
+ }
+
+ h.Padding = (rawPacket[0] >> paddingShift & paddingMask) > 0
+ h.Count = rawPacket[0] >> countShift & countMask
+
+ h.Type = PacketType(rawPacket[1])
+
+ h.Length = binary.BigEndian.Uint16(rawPacket[2:])
+
+ return nil
+}
diff --git a/vendor/github.com/pion/rtcp/packet.go b/vendor/github.com/pion/rtcp/packet.go
new file mode 100644
index 0000000..de08003
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/packet.go
@@ -0,0 +1,115 @@
+package rtcp
+
+// Packet represents an RTCP packet, a protocol used for out-of-band statistics and control information for an RTP session
+type Packet interface {
+ // DestinationSSRC returns an array of SSRC values that this packet refers to.
+ DestinationSSRC() []uint32
+
+ Marshal() ([]byte, error)
+ Unmarshal(rawPacket []byte) error
+}
+
+// Unmarshal takes an entire udp datagram (which may consist of multiple RTCP packets) and
+// returns the unmarshaled packets it contains.
+//
+// If this is a reduced-size RTCP packet a feedback packet (Goodbye, SliceLossIndication, etc)
+// will be returned. Otherwise, the underlying type of the returned packet will be
+// CompoundPacket.
+func Unmarshal(rawData []byte) ([]Packet, error) {
+ var packets []Packet
+ for len(rawData) != 0 {
+ p, processed, err := unmarshal(rawData)
+ if err != nil {
+ return nil, err
+ }
+
+ packets = append(packets, p)
+ rawData = rawData[processed:]
+ }
+
+ switch len(packets) {
+ // Empty packet
+ case 0:
+ return nil, errInvalidHeader
+ // Multiple Packets
+ default:
+ return packets, nil
+ }
+}
+
+// Marshal takes an array of Packets and serializes them to a single buffer
+func Marshal(packets []Packet) ([]byte, error) {
+ out := make([]byte, 0)
+ for _, p := range packets {
+ data, err := p.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ out = append(out, data...)
+ }
+ return out, nil
+}
+
+// unmarshal is a factory which pulls the first RTCP packet from a bytestream,
+// and returns it's parsed representation, and the amount of data that was processed.
+func unmarshal(rawData []byte) (packet Packet, bytesprocessed int, err error) {
+ var h Header
+
+ err = h.Unmarshal(rawData)
+ if err != nil {
+ return nil, 0, err
+ }
+
+ bytesprocessed = int(h.Length+1) * 4
+ if bytesprocessed > len(rawData) {
+ return nil, 0, errPacketTooShort
+ }
+ inPacket := rawData[:bytesprocessed]
+
+ switch h.Type {
+ case TypeSenderReport:
+ packet = new(SenderReport)
+
+ case TypeReceiverReport:
+ packet = new(ReceiverReport)
+
+ case TypeSourceDescription:
+ packet = new(SourceDescription)
+
+ case TypeGoodbye:
+ packet = new(Goodbye)
+
+ case TypeTransportSpecificFeedback:
+ switch h.Count {
+ case FormatTLN:
+ packet = new(TransportLayerNack)
+ case FormatRRR:
+ packet = new(RapidResynchronizationRequest)
+ case FormatTCC:
+ packet = new(TransportLayerCC)
+ default:
+ packet = new(RawPacket)
+ }
+
+ case TypePayloadSpecificFeedback:
+ switch h.Count {
+ case FormatPLI:
+ packet = new(PictureLossIndication)
+ case FormatSLI:
+ packet = new(SliceLossIndication)
+ case FormatREMB:
+ packet = new(ReceiverEstimatedMaximumBitrate)
+ case FormatFIR:
+ packet = new(FullIntraRequest)
+ default:
+ packet = new(RawPacket)
+ }
+
+ default:
+ packet = new(RawPacket)
+ }
+
+ err = packet.Unmarshal(inPacket)
+
+ return packet, bytesprocessed, err
+}
diff --git a/vendor/github.com/pion/rtcp/picture_loss_indication.go b/vendor/github.com/pion/rtcp/picture_loss_indication.go
new file mode 100644
index 0000000..7216ecd
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/picture_loss_indication.go
@@ -0,0 +1,91 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// The PictureLossIndication packet informs the encoder about the loss of an undefined amount of coded video data belonging to one or more pictures
+type PictureLossIndication struct {
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // SSRC where the loss was experienced
+ MediaSSRC uint32
+}
+
+var _ Packet = (*PictureLossIndication)(nil) // assert is a Packet
+
+const (
+ pliLength = 2
+)
+
+// Marshal encodes the PictureLossIndication in binary
+func (p PictureLossIndication) Marshal() ([]byte, error) {
+ /*
+ * PLI does not require parameters. Therefore, the length field MUST be
+ * 2, and there MUST NOT be any Feedback Control Information.
+ *
+ * The semantics of this FB message is independent of the payload type.
+ */
+ rawPacket := make([]byte, p.len())
+ packetBody := rawPacket[headerLength:]
+
+ binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
+ binary.BigEndian.PutUint32(packetBody[4:], p.MediaSSRC)
+
+ h := Header{
+ Count: FormatPLI,
+ Type: TypePayloadSpecificFeedback,
+ Length: pliLength,
+ }
+ hData, err := h.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the PictureLossIndication from binary
+func (p *PictureLossIndication) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < (headerLength + (ssrcLength * 2)) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if h.Type != TypePayloadSpecificFeedback || h.Count != FormatPLI {
+ return errWrongType
+ }
+
+ p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ return nil
+}
+
+// Header returns the Header associated with this packet.
+func (p *PictureLossIndication) Header() Header {
+ return Header{
+ Count: FormatPLI,
+ Type: TypePayloadSpecificFeedback,
+ Length: pliLength,
+ }
+}
+
+func (p *PictureLossIndication) len() int {
+ return headerLength + ssrcLength*2
+}
+
+func (p *PictureLossIndication) String() string {
+ return fmt.Sprintf("PictureLossIndication %x %x", p.SenderSSRC, p.MediaSSRC)
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *PictureLossIndication) DestinationSSRC() []uint32 {
+ return []uint32{p.MediaSSRC}
+}
diff --git a/vendor/github.com/pion/rtcp/rapid_resynchronization_request.go b/vendor/github.com/pion/rtcp/rapid_resynchronization_request.go
new file mode 100644
index 0000000..5d27055
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/rapid_resynchronization_request.go
@@ -0,0 +1,88 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// The RapidResynchronizationRequest packet informs the encoder about the loss of an undefined amount of coded video data belonging to one or more pictures
+type RapidResynchronizationRequest struct {
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // SSRC of the media source
+ MediaSSRC uint32
+}
+
+var _ Packet = (*RapidResynchronizationRequest)(nil) // assert is a Packet
+
+const (
+ rrrLength = 2
+ rrrHeaderLength = ssrcLength * 2
+ rrrMediaOffset = 4
+)
+
+// Marshal encodes the RapidResynchronizationRequest in binary
+func (p RapidResynchronizationRequest) Marshal() ([]byte, error) {
+ /*
+ * RRR does not require parameters. Therefore, the length field MUST be
+ * 2, and there MUST NOT be any Feedback Control Information.
+ *
+ * The semantics of this FB message is independent of the payload type.
+ */
+ rawPacket := make([]byte, p.len())
+ packetBody := rawPacket[headerLength:]
+
+ binary.BigEndian.PutUint32(packetBody, p.SenderSSRC)
+ binary.BigEndian.PutUint32(packetBody[rrrMediaOffset:], p.MediaSSRC)
+
+ hData, err := p.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the RapidResynchronizationRequest from binary
+func (p *RapidResynchronizationRequest) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < (headerLength + (ssrcLength * 2)) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if h.Type != TypeTransportSpecificFeedback || h.Count != FormatRRR {
+ return errWrongType
+ }
+
+ p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ return nil
+}
+
+func (p *RapidResynchronizationRequest) len() int {
+ return headerLength + rrrHeaderLength
+}
+
+// Header returns the Header associated with this packet.
+func (p *RapidResynchronizationRequest) Header() Header {
+ return Header{
+ Count: FormatRRR,
+ Type: TypeTransportSpecificFeedback,
+ Length: rrrLength,
+ }
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *RapidResynchronizationRequest) DestinationSSRC() []uint32 {
+ return []uint32{p.MediaSSRC}
+}
+
+func (p *RapidResynchronizationRequest) String() string {
+ return fmt.Sprintf("RapidResynchronizationRequest %x %x", p.SenderSSRC, p.MediaSSRC)
+}
diff --git a/vendor/github.com/pion/rtcp/raw_packet.go b/vendor/github.com/pion/rtcp/raw_packet.go
new file mode 100644
index 0000000..3cb6eaf
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/raw_packet.go
@@ -0,0 +1,44 @@
+package rtcp
+
+import "fmt"
+
+// RawPacket represents an unparsed RTCP packet. It's returned by Unmarshal when
+// a packet with an unknown type is encountered.
+type RawPacket []byte
+
+var _ Packet = (*RawPacket)(nil) // assert is a Packet
+
+// Marshal encodes the packet in binary.
+func (r RawPacket) Marshal() ([]byte, error) {
+ return r, nil
+}
+
+// Unmarshal decodes the packet from binary.
+func (r *RawPacket) Unmarshal(b []byte) error {
+ if len(b) < (headerLength) {
+ return errPacketTooShort
+ }
+ *r = b
+
+ var h Header
+ return h.Unmarshal(b)
+}
+
+// Header returns the Header associated with this packet.
+func (r RawPacket) Header() Header {
+ var h Header
+ if err := h.Unmarshal(r); err != nil {
+ return Header{}
+ }
+ return h
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (r *RawPacket) DestinationSSRC() []uint32 {
+ return []uint32{}
+}
+
+func (r RawPacket) String() string {
+ out := fmt.Sprintf("RawPacket: %v", ([]byte)(r))
+ return out
+}
diff --git a/vendor/github.com/pion/rtcp/receiver_estimated_maximum_bitrate.go b/vendor/github.com/pion/rtcp/receiver_estimated_maximum_bitrate.go
new file mode 100644
index 0000000..d37f49e
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/receiver_estimated_maximum_bitrate.go
@@ -0,0 +1,284 @@
+package rtcp
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "math/bits"
+)
+
+// ReceiverEstimatedMaximumBitrate contains the receiver's estimated maximum bitrate.
+// see: https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03
+type ReceiverEstimatedMaximumBitrate struct {
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // Estimated maximum bitrate
+ Bitrate uint64
+
+ // SSRC entries which this packet applies to
+ SSRCs []uint32
+}
+
+var _ Packet = (*ReceiverEstimatedMaximumBitrate)(nil) // assert is a Packet
+
+// Marshal serializes the packet and returns a byte slice.
+func (p ReceiverEstimatedMaximumBitrate) Marshal() (buf []byte, err error) {
+ // Allocate a buffer of the exact output size.
+ buf = make([]byte, p.MarshalSize())
+
+ // Write to our buffer.
+ n, err := p.MarshalTo(buf)
+ if err != nil {
+ return nil, err
+ }
+
+ // This will always be true but just to be safe.
+ if n != len(buf) {
+ return nil, errWrongMarshalSize
+ }
+
+ return buf, nil
+}
+
+// MarshalSize returns the size of the packet when marshaled.
+// This can be used in conjunction with `MarshalTo` to avoid allocations.
+func (p ReceiverEstimatedMaximumBitrate) MarshalSize() (n int) {
+ return 20 + 4*len(p.SSRCs)
+}
+
+// MarshalTo serializes the packet to the given byte slice.
+func (p ReceiverEstimatedMaximumBitrate) MarshalTo(buf []byte) (n int, err error) {
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |V=2|P| FMT=15 | PT=206 | length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC of packet sender |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC of media source |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unique identifier 'R' 'E' 'M' 'B' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Num SSRC | BR Exp | BR Mantissa |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC feedback |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... |
+ */
+
+ size := p.MarshalSize()
+ if len(buf) < size {
+ return 0, errPacketTooShort
+ }
+
+ buf[0] = 143 // v=2, p=0, fmt=15
+ buf[1] = 206
+
+ // Length of this packet in 32-bit words minus one.
+ length := uint16((p.MarshalSize() / 4) - 1)
+ binary.BigEndian.PutUint16(buf[2:4], length)
+
+ binary.BigEndian.PutUint32(buf[4:8], p.SenderSSRC)
+ binary.BigEndian.PutUint32(buf[8:12], 0) // always zero
+
+ // ALL HAIL REMB
+ buf[12] = 'R'
+ buf[13] = 'E'
+ buf[14] = 'M'
+ buf[15] = 'B'
+
+ // Write the length of the ssrcs to follow at the end
+ buf[16] = byte(len(p.SSRCs))
+
+ // We can only encode 18 bits of information in the mantissa.
+ // The exponent lets us shift to the left up to 64 places (6-bits).
+ // We actually need a uint82 to encode the largest possible number,
+ // but uint64 should be good enough for 2.3 exabytes per second.
+
+ // So we need to truncate the bitrate and use the exponent for the shift.
+ // bitrate = mantissa * (1 << exp)
+
+ // Calculate the total shift based on the leading number of zeroes.
+ // This will be negative if there is no shift required.
+ shift := uint(64 - bits.LeadingZeros64(p.Bitrate))
+
+ var mantissa uint
+ var exp uint
+
+ if shift <= 18 {
+ // Fit everything in the mantissa because we can.
+ mantissa = uint(p.Bitrate)
+ exp = 0
+ } else {
+ // We can only use 18 bits of precision, so truncate.
+ mantissa = uint(p.Bitrate >> (shift - 18))
+ exp = shift - 18
+ }
+
+ // We can't quite use the binary package because
+ // a) it's a uint24 and b) the exponent is only 6-bits
+ // Just trust me; this is big-endian encoding.
+ buf[17] = byte((exp << 2) | (mantissa >> 16))
+ buf[18] = byte(mantissa >> 8)
+ buf[19] = byte(mantissa)
+
+ // Write the SSRCs at the very end.
+ n = 20
+ for _, ssrc := range p.SSRCs {
+ binary.BigEndian.PutUint32(buf[n:n+4], ssrc)
+ n += 4
+ }
+
+ return n, nil
+}
+
+// Unmarshal reads a REMB packet from the given byte slice.
+func (p *ReceiverEstimatedMaximumBitrate) Unmarshal(buf []byte) (err error) {
+ /*
+ 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
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ |V=2|P| FMT=15 | PT=206 | length |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC of packet sender |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC of media source |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Unique identifier 'R' 'E' 'M' 'B' |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | Num SSRC | BR Exp | BR Mantissa |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | SSRC feedback |
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ | ... |
+ */
+
+ // 20 bytes is the size of the packet with no SSRCs
+ if len(buf) < 20 {
+ return errPacketTooShort
+ }
+
+ // version must be 2
+ version := buf[0] >> 6
+ if version != 2 {
+ return fmt.Errorf("%w expected(2) actual(%d)", errBadVersion, version)
+ }
+
+ // padding must be unset
+ padding := (buf[0] >> 5) & 1
+ if padding != 0 {
+ return fmt.Errorf("%w expected(0) actual(%d)", errWrongPadding, padding)
+ }
+
+ // fmt must be 15
+ fmtVal := buf[0] & 31
+ if fmtVal != 15 {
+ return fmt.Errorf("%w expected(15) actual(%d)", errWrongFeedbackType, fmtVal)
+ }
+
+ // Must be payload specific feedback
+ if buf[1] != 206 {
+ return fmt.Errorf("%w expected(206) actual(%d)", errWrongPayloadType, buf[1])
+ }
+
+ // length is the number of 32-bit words, minus 1
+ length := binary.BigEndian.Uint16(buf[2:4])
+ size := int((length + 1) * 4)
+
+ // There's not way this could be legit
+ if size < 20 {
+ return errHeaderTooSmall
+ }
+
+ // Make sure the buffer is large enough.
+ if len(buf) < size {
+ return errPacketTooShort
+ }
+
+ // The sender SSRC is 32-bits
+ p.SenderSSRC = binary.BigEndian.Uint32(buf[4:8])
+
+ // The destination SSRC must be 0
+ media := binary.BigEndian.Uint32(buf[8:12])
+ if media != 0 {
+ return errSSRCMustBeZero
+ }
+
+ // REMB rules all around me
+ if !bytes.Equal(buf[12:16], []byte{'R', 'E', 'M', 'B'}) {
+ return errMissingREMBidentifier
+ }
+
+ // The next byte is the number of SSRC entries at the end.
+ num := int(buf[16])
+
+ // Now we know the expected size, make sure they match.
+ if size != 20+4*num {
+ return errSSRCNumAndLengthMismatch
+ }
+
+ // Get the 6-bit exponent value.
+ exp := buf[17] >> 2
+
+ // The remaining 2-bits plus the next 16-bits are the mantissa.
+ mantissa := uint64(buf[17]&3)<<16 | uint64(buf[18])<<8 | uint64(buf[19])
+
+ // bitrate = mantissa * 2^exp
+
+ if exp > 46 {
+ // NOTE: We intentionally truncate values so they fit in a uint64.
+ // Otherwise we would need a uint82.
+ // This is 2.3 exabytes per second, which should be good enough.
+ p.Bitrate = ^uint64(0)
+ } else {
+ p.Bitrate = mantissa << exp
+ }
+
+ // Clear any existing SSRCs
+ p.SSRCs = nil
+
+ // Loop over and parse the SSRC entires at the end.
+ // We already verified that size == num * 4
+ for n := 20; n < size; n += 4 {
+ ssrc := binary.BigEndian.Uint32(buf[n : n+4])
+ p.SSRCs = append(p.SSRCs, ssrc)
+ }
+
+ return nil
+}
+
+// Header returns the Header associated with this packet.
+func (p *ReceiverEstimatedMaximumBitrate) Header() Header {
+ return Header{
+ Count: FormatREMB,
+ Type: TypePayloadSpecificFeedback,
+ Length: uint16((p.MarshalSize() / 4) - 1),
+ }
+}
+
+// String prints the REMB packet in a human-readable format.
+func (p *ReceiverEstimatedMaximumBitrate) String() string {
+ // Keep a table of powers to units for fast conversion.
+ bitUnits := []string{"b", "Kb", "Mb", "Gb", "Tb", "Pb", "Eb"}
+
+ // Do some unit conversions because b/s is far too difficult to read.
+ bitrate := float64(p.Bitrate)
+ powers := 0
+
+ // Keep dividing the bitrate until it's under 1000
+ for bitrate >= 1000.0 && powers < len(bitUnits) {
+ bitrate /= 1000.0
+ powers++
+ }
+
+ unit := bitUnits[powers]
+
+ return fmt.Sprintf("ReceiverEstimatedMaximumBitrate %x %.2f %s/s", p.SenderSSRC, bitrate, unit)
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *ReceiverEstimatedMaximumBitrate) DestinationSSRC() []uint32 {
+ return p.SSRCs
+}
diff --git a/vendor/github.com/pion/rtcp/receiver_report.go b/vendor/github.com/pion/rtcp/receiver_report.go
new file mode 100644
index 0000000..cf28d39
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/receiver_report.go
@@ -0,0 +1,193 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// A ReceiverReport (RR) packet provides reception quality feedback for an RTP stream
+type ReceiverReport struct {
+ // The synchronization source identifier for the originator of this RR packet.
+ SSRC uint32
+ // Zero or more reception report blocks depending on the number of other
+ // sources heard by this sender since the last report. Each reception report
+ // block conveys statistics on the reception of RTP packets from a
+ // single synchronization source.
+ Reports []ReceptionReport
+ // Extension contains additional, payload-specific information that needs to
+ // be reported regularly about the receiver.
+ ProfileExtensions []byte
+}
+
+var _ Packet = (*ReceiverReport)(nil) // assert is a Packet
+
+const (
+ ssrcLength = 4
+ rrSSRCOffset = headerLength
+ rrReportOffset = rrSSRCOffset + ssrcLength
+)
+
+// Marshal encodes the ReceiverReport in binary
+func (r ReceiverReport) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| RC | PT=RR=201 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC of packet sender |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_1 (SSRC of first source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_2 (SSRC of second source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | profile-specific extensions |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ rawPacket := make([]byte, r.len())
+ packetBody := rawPacket[headerLength:]
+
+ binary.BigEndian.PutUint32(packetBody, r.SSRC)
+
+ for i, rp := range r.Reports {
+ data, err := rp.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ offset := ssrcLength + receptionReportLength*i
+ copy(packetBody[offset:], data)
+ }
+
+ if len(r.Reports) > countMax {
+ return nil, errTooManyReports
+ }
+
+ pe := make([]byte, len(r.ProfileExtensions))
+ copy(pe, r.ProfileExtensions)
+
+ // if the length of the profile extensions isn't devisible
+ // by 4, we need to pad the end.
+ for (len(pe) & 0x3) != 0 {
+ pe = append(pe, 0)
+ }
+
+ rawPacket = append(rawPacket, pe...)
+
+ hData, err := r.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the ReceiverReport from binary
+func (r *ReceiverReport) Unmarshal(rawPacket []byte) error {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| RC | PT=RR=201 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC of packet sender |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_1 (SSRC of first source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_2 (SSRC of second source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | profile-specific extensions |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ if len(rawPacket) < (headerLength + ssrcLength) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if h.Type != TypeReceiverReport {
+ return errWrongType
+ }
+
+ r.SSRC = binary.BigEndian.Uint32(rawPacket[rrSSRCOffset:])
+
+ for i := rrReportOffset; i < len(rawPacket) && len(r.Reports) < int(h.Count); i += receptionReportLength {
+ var rr ReceptionReport
+ if err := rr.Unmarshal(rawPacket[i:]); err != nil {
+ return err
+ }
+ r.Reports = append(r.Reports, rr)
+ }
+ r.ProfileExtensions = rawPacket[rrReportOffset+(len(r.Reports)*receptionReportLength):]
+
+ if uint8(len(r.Reports)) != h.Count {
+ return errInvalidHeader
+ }
+
+ return nil
+}
+
+func (r *ReceiverReport) len() int {
+ repsLength := 0
+ for _, rep := range r.Reports {
+ repsLength += rep.len()
+ }
+ return headerLength + ssrcLength + repsLength
+}
+
+// Header returns the Header associated with this packet.
+func (r *ReceiverReport) Header() Header {
+ return Header{
+ Count: uint8(len(r.Reports)),
+ Type: TypeReceiverReport,
+ Length: uint16((r.len()/4)-1) + uint16(getPadding(len(r.ProfileExtensions))),
+ }
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (r *ReceiverReport) DestinationSSRC() []uint32 {
+ out := make([]uint32, len(r.Reports))
+ for i, v := range r.Reports {
+ out[i] = v.SSRC
+ }
+ return out
+}
+
+func (r ReceiverReport) String() string {
+ out := fmt.Sprintf("ReceiverReport from %x\n", r.SSRC)
+ out += "\tSSRC \tLost\tLastSequence\n"
+ for _, i := range r.Reports {
+ out += fmt.Sprintf("\t%x\t%d/%d\t%d\n", i.SSRC, i.FractionLost, i.TotalLost, i.LastSequenceNumber)
+ }
+ out += fmt.Sprintf("\tProfile Extension Data: %v\n", r.ProfileExtensions)
+ return out
+}
diff --git a/vendor/github.com/pion/rtcp/reception_report.go b/vendor/github.com/pion/rtcp/reception_report.go
new file mode 100644
index 0000000..5bff8f2
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/reception_report.go
@@ -0,0 +1,130 @@
+package rtcp
+
+import "encoding/binary"
+
+// A ReceptionReport block conveys statistics on the reception of RTP packets
+// from a single synchronization source.
+type ReceptionReport struct {
+ // The SSRC identifier of the source to which the information in this
+ // reception report block pertains.
+ SSRC uint32
+ // The fraction of RTP data packets from source SSRC lost since the
+ // previous SR or RR packet was sent, expressed as a fixed point
+ // number with the binary point at the left edge of the field.
+ FractionLost uint8
+ // The total number of RTP data packets from source SSRC that have
+ // been lost since the beginning of reception.
+ TotalLost uint32
+ // The low 16 bits contain the highest sequence number received in an
+ // RTP data packet from source SSRC, and the most significant 16
+ // bits extend that sequence number with the corresponding count of
+ // sequence number cycles.
+ LastSequenceNumber uint32
+ // An estimate of the statistical variance of the RTP data packet
+ // interarrival time, measured in timestamp units and expressed as an
+ // unsigned integer.
+ Jitter uint32
+ // The middle 32 bits out of 64 in the NTP timestamp received as part of
+ // the most recent RTCP sender report (SR) packet from source SSRC. If no
+ // SR has been received yet, the field is set to zero.
+ LastSenderReport uint32
+ // The delay, expressed in units of 1/65536 seconds, between receiving the
+ // last SR packet from source SSRC and sending this reception report block.
+ // If no SR packet has been received yet from SSRC, the field is set to zero.
+ Delay uint32
+}
+
+const (
+ receptionReportLength = 24
+ fractionLostOffset = 4
+ totalLostOffset = 5
+ lastSeqOffset = 8
+ jitterOffset = 12
+ lastSROffset = 16
+ delayOffset = 20
+)
+
+// Marshal encodes the ReceptionReport in binary
+func (r ReceptionReport) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | SSRC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ rawPacket := make([]byte, receptionReportLength)
+
+ binary.BigEndian.PutUint32(rawPacket, r.SSRC)
+
+ rawPacket[fractionLostOffset] = r.FractionLost
+
+ // pack TotalLost into 24 bits
+ if r.TotalLost >= (1 << 25) {
+ return nil, errInvalidTotalLost
+ }
+ tlBytes := rawPacket[totalLostOffset:]
+ tlBytes[0] = byte(r.TotalLost >> 16)
+ tlBytes[1] = byte(r.TotalLost >> 8)
+ tlBytes[2] = byte(r.TotalLost)
+
+ binary.BigEndian.PutUint32(rawPacket[lastSeqOffset:], r.LastSequenceNumber)
+ binary.BigEndian.PutUint32(rawPacket[jitterOffset:], r.Jitter)
+ binary.BigEndian.PutUint32(rawPacket[lastSROffset:], r.LastSenderReport)
+ binary.BigEndian.PutUint32(rawPacket[delayOffset:], r.Delay)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the ReceptionReport from binary
+func (r *ReceptionReport) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < receptionReportLength {
+ return errPacketTooShort
+ }
+
+ /*
+ * 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
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | SSRC |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ r.SSRC = binary.BigEndian.Uint32(rawPacket)
+ r.FractionLost = rawPacket[fractionLostOffset]
+
+ tlBytes := rawPacket[totalLostOffset:]
+ r.TotalLost = uint32(tlBytes[2]) | uint32(tlBytes[1])<<8 | uint32(tlBytes[0])<<16
+
+ r.LastSequenceNumber = binary.BigEndian.Uint32(rawPacket[lastSeqOffset:])
+ r.Jitter = binary.BigEndian.Uint32(rawPacket[jitterOffset:])
+ r.LastSenderReport = binary.BigEndian.Uint32(rawPacket[lastSROffset:])
+ r.Delay = binary.BigEndian.Uint32(rawPacket[delayOffset:])
+
+ return nil
+}
+
+func (r *ReceptionReport) len() int {
+ return receptionReportLength
+}
diff --git a/vendor/github.com/pion/rtcp/renovate.json b/vendor/github.com/pion/rtcp/renovate.json
new file mode 100644
index 0000000..4400fd9
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/renovate.json
@@ -0,0 +1,15 @@
+{
+ "extends": [
+ "config:base"
+ ],
+ "postUpdateOptions": [
+ "gomodTidy"
+ ],
+ "commitBody": "Generated by renovateBot",
+ "packageRules": [
+ {
+ "packagePatterns": ["^golang.org/x/"],
+ "schedule": ["on the first day of the month"]
+ }
+ ]
+}
diff --git a/vendor/github.com/pion/rtcp/sender_report.go b/vendor/github.com/pion/rtcp/sender_report.go
new file mode 100644
index 0000000..1b16380
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/sender_report.go
@@ -0,0 +1,260 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// A SenderReport (SR) packet provides reception quality feedback for an RTP stream
+type SenderReport struct {
+ // The synchronization source identifier for the originator of this SR packet.
+ SSRC uint32
+ // The wallclock time when this report was sent so that it may be used in
+ // combination with timestamps returned in reception reports from other
+ // receivers to measure round-trip propagation to those receivers.
+ NTPTime uint64
+ // Corresponds to the same time as the NTP timestamp (above), but in
+ // the same units and with the same random offset as the RTP
+ // timestamps in data packets. This correspondence may be used for
+ // intra- and inter-media synchronization for sources whose NTP
+ // timestamps are synchronized, and may be used by media-independent
+ // receivers to estimate the nominal RTP clock frequency.
+ RTPTime uint32
+ // The total number of RTP data packets transmitted by the sender
+ // since starting transmission up until the time this SR packet was
+ // generated.
+ PacketCount uint32
+ // The total number of payload octets (i.e., not including header or
+ // padding) transmitted in RTP data packets by the sender since
+ // starting transmission up until the time this SR packet was
+ // generated.
+ OctetCount uint32
+ // Zero or more reception report blocks depending on the number of other
+ // sources heard by this sender since the last report. Each reception report
+ // block conveys statistics on the reception of RTP packets from a
+ // single synchronization source.
+ Reports []ReceptionReport
+ // ProfileExtensions contains additional, payload-specific information that needs to
+ // be reported regularly about the sender.
+ ProfileExtensions []byte
+}
+
+var _ Packet = (*SenderReport)(nil) // assert is a Packet
+
+const (
+ srHeaderLength = 24
+ srSSRCOffset = 0
+ srNTPOffset = srSSRCOffset + ssrcLength
+ ntpTimeLength = 8
+ srRTPOffset = srNTPOffset + ntpTimeLength
+ rtpTimeLength = 4
+ srPacketCountOffset = srRTPOffset + rtpTimeLength
+ srPacketCountLength = 4
+ srOctetCountOffset = srPacketCountOffset + srPacketCountLength
+ srOctetCountLength = 4
+ srReportOffset = srOctetCountOffset + srOctetCountLength
+)
+
+// Marshal encodes the SenderReport in binary
+func (r SenderReport) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| RC | PT=SR=200 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC of sender |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * sender | NTP timestamp, most significant word |
+ * info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NTP timestamp, least significant word |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RTP timestamp |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | sender's packet count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | sender's octet count |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_1 (SSRC of first source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_2 (SSRC of second source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | profile-specific extensions |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ rawPacket := make([]byte, r.len())
+ packetBody := rawPacket[headerLength:]
+
+ binary.BigEndian.PutUint32(packetBody[srSSRCOffset:], r.SSRC)
+ binary.BigEndian.PutUint64(packetBody[srNTPOffset:], r.NTPTime)
+ binary.BigEndian.PutUint32(packetBody[srRTPOffset:], r.RTPTime)
+ binary.BigEndian.PutUint32(packetBody[srPacketCountOffset:], r.PacketCount)
+ binary.BigEndian.PutUint32(packetBody[srOctetCountOffset:], r.OctetCount)
+
+ offset := srHeaderLength
+ for _, rp := range r.Reports {
+ data, err := rp.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(packetBody[offset:], data)
+ offset += receptionReportLength
+ }
+
+ if len(r.Reports) > countMax {
+ return nil, errTooManyReports
+ }
+
+ copy(packetBody[offset:], r.ProfileExtensions)
+
+ hData, err := r.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the SenderReport from binary
+func (r *SenderReport) Unmarshal(rawPacket []byte) error {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| RC | PT=SR=200 | length |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SSRC of sender |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * sender | NTP timestamp, most significant word |
+ * info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | NTP timestamp, least significant word |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | RTP timestamp |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | sender's packet count |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | sender's octet count |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_1 (SSRC of first source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 1 | fraction lost | cumulative number of packets lost |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | extended highest sequence number received |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | interarrival jitter |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | last SR (LSR) |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | delay since last SR (DLSR) |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * report | SSRC_2 (SSRC of second source) |
+ * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * 2 : ... :
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | profile-specific extensions |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ if len(rawPacket) < (headerLength + srHeaderLength) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if h.Type != TypeSenderReport {
+ return errWrongType
+ }
+
+ packetBody := rawPacket[headerLength:]
+
+ r.SSRC = binary.BigEndian.Uint32(packetBody[srSSRCOffset:])
+ r.NTPTime = binary.BigEndian.Uint64(packetBody[srNTPOffset:])
+ r.RTPTime = binary.BigEndian.Uint32(packetBody[srRTPOffset:])
+ r.PacketCount = binary.BigEndian.Uint32(packetBody[srPacketCountOffset:])
+ r.OctetCount = binary.BigEndian.Uint32(packetBody[srOctetCountOffset:])
+
+ offset := srReportOffset
+ for i := 0; i < int(h.Count); i++ {
+ rrEnd := offset + receptionReportLength
+ if rrEnd > len(packetBody) {
+ return errPacketTooShort
+ }
+ rrBody := packetBody[offset : offset+receptionReportLength]
+ offset = rrEnd
+
+ var rr ReceptionReport
+ if err := rr.Unmarshal(rrBody); err != nil {
+ return err
+ }
+ r.Reports = append(r.Reports, rr)
+ }
+
+ if offset < len(packetBody) {
+ r.ProfileExtensions = packetBody[offset:]
+ }
+
+ if uint8(len(r.Reports)) != h.Count {
+ return errInvalidHeader
+ }
+
+ return nil
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (r *SenderReport) DestinationSSRC() []uint32 {
+ out := make([]uint32, len(r.Reports)+1)
+ for i, v := range r.Reports {
+ out[i] = v.SSRC
+ }
+ out[len(r.Reports)] = r.SSRC
+ return out
+}
+
+func (r *SenderReport) len() int {
+ repsLength := 0
+ for _, rep := range r.Reports {
+ repsLength += rep.len()
+ }
+ return headerLength + srHeaderLength + repsLength + len(r.ProfileExtensions)
+}
+
+// Header returns the Header associated with this packet.
+func (r *SenderReport) Header() Header {
+ return Header{
+ Count: uint8(len(r.Reports)),
+ Type: TypeSenderReport,
+ Length: uint16((r.len() / 4) - 1),
+ }
+}
+
+func (r SenderReport) String() string {
+ out := fmt.Sprintf("SenderReport from %x\n", r.SSRC)
+ out += fmt.Sprintf("\tNTPTime:\t%d\n", r.NTPTime)
+ out += fmt.Sprintf("\tRTPTIme:\t%d\n", r.RTPTime)
+ out += fmt.Sprintf("\tPacketCount:\t%d\n", r.PacketCount)
+ out += fmt.Sprintf("\tOctetCount:\t%d\n", r.OctetCount)
+
+ out += "\tSSRC \tLost\tLastSequence\n"
+ for _, i := range r.Reports {
+ out += fmt.Sprintf("\t%x\t%d/%d\t%d\n", i.SSRC, i.FractionLost, i.TotalLost, i.LastSequenceNumber)
+ }
+ out += fmt.Sprintf("\tProfile Extension Data: %v\n", r.ProfileExtensions)
+ return out
+}
diff --git a/vendor/github.com/pion/rtcp/slice_loss_indication.go b/vendor/github.com/pion/rtcp/slice_loss_indication.go
new file mode 100644
index 0000000..7689309
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/slice_loss_indication.go
@@ -0,0 +1,115 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math"
+)
+
+// SLIEntry represents a single entry to the SLI packet's
+// list of lost slices.
+type SLIEntry struct {
+ // ID of first lost slice
+ First uint16
+
+ // Number of lost slices
+ Number uint16
+
+ // ID of related picture
+ Picture uint8
+}
+
+// The SliceLossIndication packet informs the encoder about the loss of a picture slice
+type SliceLossIndication struct {
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // SSRC of the media source
+ MediaSSRC uint32
+
+ SLI []SLIEntry
+}
+
+var _ Packet = (*SliceLossIndication)(nil) // assert is a Packet
+
+const (
+ sliLength = 2
+ sliOffset = 8
+)
+
+// Marshal encodes the SliceLossIndication in binary
+func (p SliceLossIndication) Marshal() ([]byte, error) {
+ if len(p.SLI)+sliLength > math.MaxUint8 {
+ return nil, errTooManyReports
+ }
+
+ rawPacket := make([]byte, sliOffset+(len(p.SLI)*4))
+ binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
+ binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
+ for i, s := range p.SLI {
+ sli := ((uint32(s.First) & 0x1FFF) << 19) |
+ ((uint32(s.Number) & 0x1FFF) << 6) |
+ (uint32(s.Picture) & 0x3F)
+ binary.BigEndian.PutUint32(rawPacket[sliOffset+(4*i):], sli)
+ }
+ hData, err := p.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ return append(hData, rawPacket...), nil
+}
+
+// Unmarshal decodes the SliceLossIndication from binary
+func (p *SliceLossIndication) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < (headerLength + ssrcLength) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if len(rawPacket) < (headerLength + int(4*h.Length)) {
+ return errPacketTooShort
+ }
+
+ if h.Type != TypeTransportSpecificFeedback || h.Count != FormatSLI {
+ return errWrongType
+ }
+
+ p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ for i := headerLength + sliOffset; i < (headerLength + int(h.Length*4)); i += 4 {
+ sli := binary.BigEndian.Uint32(rawPacket[i:])
+ p.SLI = append(p.SLI, SLIEntry{
+ First: uint16((sli >> 19) & 0x1FFF),
+ Number: uint16((sli >> 6) & 0x1FFF),
+ Picture: uint8(sli & 0x3F),
+ })
+ }
+ return nil
+}
+
+func (p *SliceLossIndication) len() int {
+ return headerLength + sliOffset + (len(p.SLI) * 4)
+}
+
+// Header returns the Header associated with this packet.
+func (p *SliceLossIndication) Header() Header {
+ return Header{
+ Count: FormatSLI,
+ Type: TypeTransportSpecificFeedback,
+ Length: uint16((p.len() / 4) - 1),
+ }
+}
+
+func (p *SliceLossIndication) String() string {
+ return fmt.Sprintf("SliceLossIndication %x %x %+v", p.SenderSSRC, p.MediaSSRC, p.SLI)
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *SliceLossIndication) DestinationSSRC() []uint32 {
+ return []uint32{p.MediaSSRC}
+}
diff --git a/vendor/github.com/pion/rtcp/source_description.go b/vendor/github.com/pion/rtcp/source_description.go
new file mode 100644
index 0000000..4306b66
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/source_description.go
@@ -0,0 +1,352 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+)
+
+// SDESType is the item type used in the RTCP SDES control packet.
+type SDESType uint8
+
+// RTP SDES item types registered with IANA. See: https://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml#rtp-parameters-5
+const (
+ SDESEnd SDESType = iota // end of SDES list RFC 3550, 6.5
+ SDESCNAME // canonical name RFC 3550, 6.5.1
+ SDESName // user name RFC 3550, 6.5.2
+ SDESEmail // user's electronic mail address RFC 3550, 6.5.3
+ SDESPhone // user's phone number RFC 3550, 6.5.4
+ SDESLocation // geographic user location RFC 3550, 6.5.5
+ SDESTool // name of application or tool RFC 3550, 6.5.6
+ SDESNote // notice about the source RFC 3550, 6.5.7
+ SDESPrivate // private extensions RFC 3550, 6.5.8 (not implemented)
+)
+
+func (s SDESType) String() string {
+ switch s {
+ case SDESEnd:
+ return "END"
+ case SDESCNAME:
+ return "CNAME"
+ case SDESName:
+ return "NAME"
+ case SDESEmail:
+ return "EMAIL"
+ case SDESPhone:
+ return "PHONE"
+ case SDESLocation:
+ return "LOC"
+ case SDESTool:
+ return "TOOL"
+ case SDESNote:
+ return "NOTE"
+ case SDESPrivate:
+ return "PRIV"
+ default:
+ return string(s)
+ }
+}
+
+const (
+ sdesSourceLen = 4
+ sdesTypeLen = 1
+ sdesTypeOffset = 0
+ sdesOctetCountLen = 1
+ sdesOctetCountOffset = 1
+ sdesMaxOctetCount = (1 << 8) - 1
+ sdesTextOffset = 2
+)
+
+// A SourceDescription (SDES) packet describes the sources in an RTP stream.
+type SourceDescription struct {
+ Chunks []SourceDescriptionChunk
+}
+
+var _ Packet = (*SourceDescription)(nil) // assert is a Packet
+
+// Marshal encodes the SourceDescription in binary
+func (s SourceDescription) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| SC | PT=SDES=202 | length |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * chunk | SSRC/CSRC_1 |
+ * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * chunk | SSRC/CSRC_2 |
+ * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ rawPacket := make([]byte, s.len())
+ packetBody := rawPacket[headerLength:]
+
+ chunkOffset := 0
+ for _, c := range s.Chunks {
+ data, err := c.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(packetBody[chunkOffset:], data)
+ chunkOffset += len(data)
+ }
+
+ if len(s.Chunks) > countMax {
+ return nil, errTooManyChunks
+ }
+
+ hData, err := s.Header().Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(rawPacket, hData)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the SourceDescription from binary
+func (s *SourceDescription) Unmarshal(rawPacket []byte) error {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * header |V=2|P| SC | PT=SDES=202 | length |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * chunk | SSRC/CSRC_1 |
+ * 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * chunk | SSRC/CSRC_2 |
+ * 2 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if h.Type != TypeSourceDescription {
+ return errWrongType
+ }
+
+ for i := headerLength; i < len(rawPacket); {
+ var chunk SourceDescriptionChunk
+ if err := chunk.Unmarshal(rawPacket[i:]); err != nil {
+ return err
+ }
+ s.Chunks = append(s.Chunks, chunk)
+
+ i += chunk.len()
+ }
+
+ if len(s.Chunks) != int(h.Count) {
+ return errInvalidHeader
+ }
+
+ return nil
+}
+
+func (s *SourceDescription) len() int {
+ chunksLength := 0
+ for _, c := range s.Chunks {
+ chunksLength += c.len()
+ }
+ return headerLength + chunksLength
+}
+
+// Header returns the Header associated with this packet.
+func (s *SourceDescription) Header() Header {
+ return Header{
+ Count: uint8(len(s.Chunks)),
+ Type: TypeSourceDescription,
+ Length: uint16((s.len() / 4) - 1),
+ }
+}
+
+// A SourceDescriptionChunk contains items describing a single RTP source
+type SourceDescriptionChunk struct {
+ // The source (ssrc) or contributing source (csrc) identifier this packet describes
+ Source uint32
+ Items []SourceDescriptionItem
+}
+
+// Marshal encodes the SourceDescriptionChunk in binary
+func (s SourceDescriptionChunk) Marshal() ([]byte, error) {
+ /*
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | SSRC/CSRC_1 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ rawPacket := make([]byte, sdesSourceLen)
+ binary.BigEndian.PutUint32(rawPacket, s.Source)
+
+ for _, it := range s.Items {
+ data, err := it.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ rawPacket = append(rawPacket, data...)
+ }
+
+ // The list of items in each chunk MUST be terminated by one or more null octets
+ rawPacket = append(rawPacket, uint8(SDESEnd))
+
+ // additional null octets MUST be included if needed to pad until the next 32-bit boundary
+ rawPacket = append(rawPacket, make([]byte, getPadding(len(rawPacket)))...)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the SourceDescriptionChunk from binary
+func (s *SourceDescriptionChunk) Unmarshal(rawPacket []byte) error {
+ /*
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ * | SSRC/CSRC_1 |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | SDES items |
+ * | ... |
+ * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
+ */
+
+ if len(rawPacket) < (sdesSourceLen + sdesTypeLen) {
+ return errPacketTooShort
+ }
+
+ s.Source = binary.BigEndian.Uint32(rawPacket)
+
+ for i := 4; i < len(rawPacket); {
+ if pktType := SDESType(rawPacket[i]); pktType == SDESEnd {
+ return nil
+ }
+
+ var it SourceDescriptionItem
+ if err := it.Unmarshal(rawPacket[i:]); err != nil {
+ return err
+ }
+ s.Items = append(s.Items, it)
+ i += it.len()
+ }
+
+ return errPacketTooShort
+}
+
+func (s SourceDescriptionChunk) len() int {
+ len := sdesSourceLen
+ for _, it := range s.Items {
+ len += it.len()
+ }
+ len += sdesTypeLen // for terminating null octet
+
+ // align to 32-bit boundary
+ len += getPadding(len)
+
+ return len
+}
+
+// A SourceDescriptionItem is a part of a SourceDescription that describes a stream.
+type SourceDescriptionItem struct {
+ // The type identifier for this item. eg, SDESCNAME for canonical name description.
+ //
+ // Type zero or SDESEnd is interpreted as the end of an item list and cannot be used.
+ Type SDESType
+ // Text is a unicode text blob associated with the item. Its meaning varies based on the item's Type.
+ Text string
+}
+
+func (s SourceDescriptionItem) len() int {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | CNAME=1 | length | user and domain name ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ return sdesTypeLen + sdesOctetCountLen + len([]byte(s.Text))
+}
+
+// Marshal encodes the SourceDescriptionItem in binary
+func (s SourceDescriptionItem) Marshal() ([]byte, error) {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | CNAME=1 | length | user and domain name ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ if s.Type == SDESEnd {
+ return nil, errSDESMissingType
+ }
+
+ rawPacket := make([]byte, sdesTypeLen+sdesOctetCountLen)
+
+ rawPacket[sdesTypeOffset] = uint8(s.Type)
+
+ txtBytes := []byte(s.Text)
+ octetCount := len(txtBytes)
+ if octetCount > sdesMaxOctetCount {
+ return nil, errSDESTextTooLong
+ }
+ rawPacket[sdesOctetCountOffset] = uint8(octetCount)
+
+ rawPacket = append(rawPacket, txtBytes...)
+
+ return rawPacket, nil
+}
+
+// Unmarshal decodes the SourceDescriptionItem from binary
+func (s *SourceDescriptionItem) Unmarshal(rawPacket []byte) error {
+ /*
+ * 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
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | CNAME=1 | length | user and domain name ...
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+ if len(rawPacket) < (sdesTypeLen + sdesOctetCountLen) {
+ return errPacketTooShort
+ }
+
+ s.Type = SDESType(rawPacket[sdesTypeOffset])
+
+ octetCount := int(rawPacket[sdesOctetCountOffset])
+ if sdesTextOffset+octetCount > len(rawPacket) {
+ return errPacketTooShort
+ }
+
+ txtBytes := rawPacket[sdesTextOffset : sdesTextOffset+octetCount]
+ s.Text = string(txtBytes)
+
+ return nil
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (s *SourceDescription) DestinationSSRC() []uint32 {
+ out := make([]uint32, len(s.Chunks))
+ for i, v := range s.Chunks {
+ out[i] = v.Source
+ }
+ return out
+}
+
+func (s *SourceDescription) String() string {
+ out := "Source Description:\n"
+ for _, c := range s.Chunks {
+ out += fmt.Sprintf("\t%x: %s\n", c.Source, c.Items)
+ }
+ return out
+}
diff --git a/vendor/github.com/pion/rtcp/transport_layer_cc.go b/vendor/github.com/pion/rtcp/transport_layer_cc.go
new file mode 100644
index 0000000..9606581
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/transport_layer_cc.go
@@ -0,0 +1,560 @@
+package rtcp
+
+// Author: adwpc
+
+import (
+ "encoding/binary"
+ "errors"
+ "fmt"
+ "math"
+)
+
+// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
+// 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
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |V=2|P| FMT=15 | PT=205 | length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of packet sender |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | SSRC of media source |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | base sequence number | packet status count |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | reference time | fb pkt. count |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | packet chunk | packet chunk |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// . .
+// . .
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | packet chunk | recv delta | recv delta |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// . .
+// . .
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// | recv delta | recv delta | zero padding |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+
+// for packet status chunk
+const (
+ // type of packet status chunk
+ TypeTCCRunLengthChunk = 0
+ TypeTCCStatusVectorChunk = 1
+
+ // len of packet status chunk
+ packetStatusChunkLength = 2
+)
+
+// type of packet status symbol and recv delta
+const (
+ // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.1
+ TypeTCCPacketNotReceived = uint16(iota)
+ TypeTCCPacketReceivedSmallDelta
+ TypeTCCPacketReceivedLargeDelta
+ // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-7
+ // see Example 2: "packet received, w/o recv delta"
+ TypeTCCPacketReceivedWithoutDelta
+)
+
+// for status vector chunk
+const (
+ // https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.4
+ TypeTCCSymbolSizeOneBit = 0
+ TypeTCCSymbolSizeTwoBit = 1
+
+ // Notice: RFC is wrong: "packet received" (0) and "packet not received" (1)
+ // if S == TypeTCCSymbolSizeOneBit, symbol list will be: TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta
+ // if S == TypeTCCSymbolSizeTwoBit, symbol list will be same as above:
+)
+
+func numOfBitsOfSymbolSize() map[uint16]uint16 {
+ return map[uint16]uint16{
+ TypeTCCSymbolSizeOneBit: 1,
+ TypeTCCSymbolSizeTwoBit: 2,
+ }
+}
+
+var _ Packet = (*TransportLayerCC)(nil) // assert is a Packet
+
+var (
+ errPacketStatusChunkLength = errors.New("packet status chunk must be 2 bytes")
+ errDeltaExceedLimit = errors.New("delta exceed limit")
+)
+
+// PacketStatusChunk has two kinds:
+// RunLengthChunk and StatusVectorChunk
+type PacketStatusChunk interface {
+ Marshal() ([]byte, error)
+ Unmarshal(rawPacket []byte) error
+}
+
+// RunLengthChunk T=TypeTCCRunLengthChunk
+// 0 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |T| S | Run Length |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+type RunLengthChunk struct {
+ PacketStatusChunk
+
+ // T = TypeTCCRunLengthChunk
+ Type uint16
+
+ // S: type of packet status
+ // kind: TypeTCCPacketNotReceived or...
+ PacketStatusSymbol uint16
+
+ // RunLength: count of S
+ RunLength uint16
+}
+
+// Marshal ..
+func (r RunLengthChunk) Marshal() ([]byte, error) {
+ chunk := make([]byte, 2)
+
+ // append 1 bit '0'
+ dst, err := setNBitsOfUint16(0, 1, 0, 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // append 2 bit PacketStatusSymbol
+ dst, err = setNBitsOfUint16(dst, 2, 1, r.PacketStatusSymbol)
+ if err != nil {
+ return nil, err
+ }
+
+ // append 13 bit RunLength
+ dst, err = setNBitsOfUint16(dst, 13, 3, r.RunLength)
+ if err != nil {
+ return nil, err
+ }
+
+ binary.BigEndian.PutUint16(chunk, dst)
+ return chunk, nil
+}
+
+// Unmarshal ..
+func (r *RunLengthChunk) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) != packetStatusChunkLength {
+ return errPacketStatusChunkLength
+ }
+
+ // record type
+ r.Type = TypeTCCRunLengthChunk
+
+ // get PacketStatusSymbol
+ // r.PacketStatusSymbol = uint16(rawPacket[0] >> 5 & 0x03)
+ r.PacketStatusSymbol = getNBitsFromByte(rawPacket[0], 1, 2)
+
+ // get RunLength
+ // r.RunLength = uint16(rawPacket[0]&0x1F)*256 + uint16(rawPacket[1])
+ r.RunLength = getNBitsFromByte(rawPacket[0], 3, 5)<<8 + uint16(rawPacket[1])
+ return nil
+}
+
+// StatusVectorChunk T=typeStatusVecotrChunk
+// 0 1
+// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+// |T|S| symbol list |
+// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+type StatusVectorChunk struct {
+ PacketStatusChunk
+ // T = TypeTCCRunLengthChunk
+ Type uint16
+
+ // TypeTCCSymbolSizeOneBit or TypeTCCSymbolSizeTwoBit
+ SymbolSize uint16
+
+ // when SymbolSize = TypeTCCSymbolSizeOneBit, SymbolList is 14*1bit:
+ // TypeTCCSymbolListPacketReceived or TypeTCCSymbolListPacketNotReceived
+ // when SymbolSize = TypeTCCSymbolSizeTwoBit, SymbolList is 7*2bit:
+ // TypeTCCPacketNotReceived TypeTCCPacketReceivedSmallDelta TypeTCCPacketReceivedLargeDelta or typePacketReserved
+ SymbolList []uint16
+}
+
+// Marshal ..
+func (r StatusVectorChunk) Marshal() ([]byte, error) {
+ chunk := make([]byte, 2)
+
+ // set first bit '1'
+ dst, err := setNBitsOfUint16(0, 1, 0, 1)
+ if err != nil {
+ return nil, err
+ }
+
+ // set second bit SymbolSize
+ dst, err = setNBitsOfUint16(dst, 1, 1, r.SymbolSize)
+ if err != nil {
+ return nil, err
+ }
+
+ numOfBits := numOfBitsOfSymbolSize()[r.SymbolSize]
+ // append 14 bit SymbolList
+ for i, s := range r.SymbolList {
+ index := numOfBits*uint16(i) + 2
+ dst, err = setNBitsOfUint16(dst, numOfBits, index, s)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ binary.BigEndian.PutUint16(chunk, dst)
+ // set SymbolList(bit8-15)
+ // chunk[1] = uint8(r.SymbolList) & 0x0f
+ return chunk, nil
+}
+
+// Unmarshal ..
+func (r *StatusVectorChunk) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) != packetStatusChunkLength {
+ return errPacketStatusChunkLength
+ }
+
+ r.Type = TypeTCCStatusVectorChunk
+ r.SymbolSize = getNBitsFromByte(rawPacket[0], 1, 1)
+
+ if r.SymbolSize == TypeTCCSymbolSizeOneBit {
+ for i := uint16(0); i < 6; i++ {
+ r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[0], 2+i, 1))
+ }
+ for i := uint16(0); i < 8; i++ {
+ r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[1], i, 1))
+ }
+ return nil
+ }
+ if r.SymbolSize == TypeTCCSymbolSizeTwoBit {
+ for i := uint16(0); i < 3; i++ {
+ r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[0], 2+i*2, 2))
+ }
+ for i := uint16(0); i < 4; i++ {
+ r.SymbolList = append(r.SymbolList, getNBitsFromByte(rawPacket[1], i*2, 2))
+ }
+ return nil
+ }
+
+ r.SymbolSize = getNBitsFromByte(rawPacket[0], 2, 6)<<8 + uint16(rawPacket[1])
+ return nil
+}
+
+const (
+ // TypeTCCDeltaScaleFactor https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5
+ TypeTCCDeltaScaleFactor = 250
+)
+
+// RecvDelta are represented as multiples of 250us
+// small delta is 1 byte: [0,63.75]ms = [0, 63750]us = [0, 255]*250us
+// big delta is 2 bytes: [-8192.0, 8191.75]ms = [-8192000, 8191750]us = [-32768, 32767]*250us
+// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#section-3.1.5
+type RecvDelta struct {
+ Type uint16
+ // us
+ Delta int64
+}
+
+// Marshal ..
+func (r RecvDelta) Marshal() ([]byte, error) {
+ delta := r.Delta / TypeTCCDeltaScaleFactor
+
+ // small delta
+ if r.Type == TypeTCCPacketReceivedSmallDelta && delta >= 0 && delta <= math.MaxUint8 {
+ deltaChunk := make([]byte, 1)
+ deltaChunk[0] = byte(delta)
+ return deltaChunk, nil
+ }
+
+ // big delta
+ if r.Type == TypeTCCPacketReceivedLargeDelta && delta >= math.MinInt16 && delta <= math.MaxInt16 {
+ deltaChunk := make([]byte, 2)
+ binary.BigEndian.PutUint16(deltaChunk, uint16(delta))
+ return deltaChunk, nil
+ }
+
+ // overflow
+ return nil, errDeltaExceedLimit
+}
+
+// Unmarshal ..
+func (r *RecvDelta) Unmarshal(rawPacket []byte) error {
+ chunkLen := len(rawPacket)
+
+ // must be 1 or 2 bytes
+ if chunkLen != 1 && chunkLen != 2 {
+ return errDeltaExceedLimit
+ }
+
+ if chunkLen == 1 {
+ r.Type = TypeTCCPacketReceivedSmallDelta
+ r.Delta = TypeTCCDeltaScaleFactor * int64(rawPacket[0])
+ return nil
+ }
+
+ r.Type = TypeTCCPacketReceivedLargeDelta
+ r.Delta = TypeTCCDeltaScaleFactor * int64(int16(binary.BigEndian.Uint16(rawPacket)))
+ return nil
+}
+
+const (
+ // the offset after header
+ baseSequenceNumberOffset = 8
+ packetStatusCountOffset = 10
+ referenceTimeOffset = 12
+ fbPktCountOffset = 15
+ packetChunkOffset = 16
+)
+
+// TransportLayerCC for sender-BWE
+// https://tools.ietf.org/html/draft-holmer-rmcat-transport-wide-cc-extensions-01#page-5
+type TransportLayerCC struct {
+ // header
+ Header Header
+
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // SSRC of the media source
+ MediaSSRC uint32
+
+ // Transport wide sequence of rtp extension
+ BaseSequenceNumber uint16
+
+ // PacketStatusCount
+ PacketStatusCount uint16
+
+ // ReferenceTime
+ ReferenceTime uint32
+
+ // FbPktCount
+ FbPktCount uint8
+
+ // PacketChunks
+ PacketChunks []PacketStatusChunk
+
+ // RecvDeltas
+ RecvDeltas []*RecvDelta
+}
+
+// Header returns the Header associated with this packet.
+// func (t *TransportLayerCC) Header() Header {
+// return t.Header
+// return Header{
+// Padding: true,
+// Count: FormatTCC,
+// Type: TypeTCCTransportSpecificFeedback,
+// // https://tools.ietf.org/html/rfc4585#page-33
+// Length: uint16((t.len() / 4) - 1),
+// }
+// }
+
+func (t *TransportLayerCC) packetLen() uint16 {
+ n := uint16(headerLength + packetChunkOffset + len(t.PacketChunks)*2)
+ for _, d := range t.RecvDeltas {
+ delta := d.Delta / TypeTCCDeltaScaleFactor
+
+ // small delta
+ if delta >= 0 && delta <= math.MaxUint8 {
+ n++
+ } else {
+ n += 2
+ }
+ }
+ return n
+}
+
+// Len return total bytes with padding
+func (t *TransportLayerCC) Len() uint16 {
+ n := t.packetLen()
+ // has padding
+ if n%4 != 0 {
+ n = (n/4 + 1) * 4
+ }
+
+ return n
+}
+
+func (t TransportLayerCC) String() string {
+ out := fmt.Sprintf("TransportLayerCC:\n\tHeader %v\n", t.Header)
+ out += fmt.Sprintf("TransportLayerCC:\n\tSender Ssrc %d\n", t.SenderSSRC)
+ out += fmt.Sprintf("\tMedia Ssrc %d\n", t.MediaSSRC)
+ out += fmt.Sprintf("\tBase Sequence Number %d\n", t.BaseSequenceNumber)
+ out += fmt.Sprintf("\tStatus Count %d\n", t.PacketStatusCount)
+ out += fmt.Sprintf("\tReference Time %d\n", t.ReferenceTime)
+ out += fmt.Sprintf("\tFeedback Packet Count %d\n", t.FbPktCount)
+ out += "\tPacketChunks "
+ for _, chunk := range t.PacketChunks {
+ out += fmt.Sprintf("%+v ", chunk)
+ }
+ out += "\n\tRecvDeltas "
+ for _, delta := range t.RecvDeltas {
+ out += fmt.Sprintf("%+v ", delta)
+ }
+ out += "\n"
+ return out
+}
+
+// Marshal encodes the TransportLayerCC in binary
+func (t TransportLayerCC) Marshal() ([]byte, error) {
+ header, err := t.Header.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ payload := make([]byte, t.Len()-headerLength)
+ binary.BigEndian.PutUint32(payload, t.SenderSSRC)
+ binary.BigEndian.PutUint32(payload[4:], t.MediaSSRC)
+ binary.BigEndian.PutUint16(payload[baseSequenceNumberOffset:], t.BaseSequenceNumber)
+ binary.BigEndian.PutUint16(payload[packetStatusCountOffset:], t.PacketStatusCount)
+ ReferenceTimeAndFbPktCount := appendNBitsToUint32(0, 24, t.ReferenceTime)
+ ReferenceTimeAndFbPktCount = appendNBitsToUint32(ReferenceTimeAndFbPktCount, 8, uint32(t.FbPktCount))
+ binary.BigEndian.PutUint32(payload[referenceTimeOffset:], ReferenceTimeAndFbPktCount)
+
+ for i, chunk := range t.PacketChunks {
+ b, err := chunk.Marshal()
+ if err != nil {
+ return nil, err
+ }
+ copy(payload[packetChunkOffset+i*2:], b)
+ }
+
+ recvDeltaOffset := packetChunkOffset + len(t.PacketChunks)*2
+ var i int
+ for _, delta := range t.RecvDeltas {
+ b, err := delta.Marshal()
+ if err == nil {
+ copy(payload[recvDeltaOffset+i:], b)
+ i++
+ if delta.Type == TypeTCCPacketReceivedLargeDelta {
+ i++
+ }
+ }
+ }
+
+ if t.Header.Padding {
+ payload[len(payload)-1] = uint8(t.Len() - t.packetLen())
+ }
+
+ return append(header, payload...), nil
+}
+
+// Unmarshal ..
+func (t *TransportLayerCC) Unmarshal(rawPacket []byte) error { //nolint:gocognit
+ if len(rawPacket) < (headerLength + ssrcLength) {
+ return errPacketTooShort
+ }
+
+ if err := t.Header.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ // https://tools.ietf.org/html/rfc4585#page-33
+ // header's length + payload's length
+ totalLength := 4 * (t.Header.Length + 1)
+
+ if totalLength <= headerLength+packetChunkOffset {
+ return errPacketTooShort
+ }
+
+ if len(rawPacket) < int(totalLength) {
+ return errPacketTooShort
+ }
+
+ if t.Header.Type != TypeTransportSpecificFeedback || t.Header.Count != FormatTCC {
+ return errWrongType
+ }
+
+ t.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ t.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ t.BaseSequenceNumber = binary.BigEndian.Uint16(rawPacket[headerLength+baseSequenceNumberOffset:])
+ t.PacketStatusCount = binary.BigEndian.Uint16(rawPacket[headerLength+packetStatusCountOffset:])
+ t.ReferenceTime = get24BitsFromBytes(rawPacket[headerLength+referenceTimeOffset : headerLength+referenceTimeOffset+3])
+ t.FbPktCount = rawPacket[headerLength+fbPktCountOffset]
+
+ packetStatusPos := uint16(headerLength + packetChunkOffset)
+ var processedPacketNum uint16
+ for processedPacketNum < t.PacketStatusCount {
+ if packetStatusPos+packetStatusChunkLength >= totalLength {
+ return errPacketTooShort
+ }
+ typ := getNBitsFromByte(rawPacket[packetStatusPos : packetStatusPos+1][0], 0, 1)
+ var iPacketStatus PacketStatusChunk
+ switch typ {
+ case TypeTCCRunLengthChunk:
+ packetStatus := &RunLengthChunk{Type: typ}
+ iPacketStatus = packetStatus
+ err := packetStatus.Unmarshal(rawPacket[packetStatusPos : packetStatusPos+2])
+ if err != nil {
+ return err
+ }
+
+ packetNumberToProcess := min(t.PacketStatusCount-processedPacketNum, packetStatus.RunLength)
+ if packetStatus.PacketStatusSymbol == TypeTCCPacketReceivedSmallDelta ||
+ packetStatus.PacketStatusSymbol == TypeTCCPacketReceivedLargeDelta {
+ for j := uint16(0); j < packetNumberToProcess; j++ {
+ t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: packetStatus.PacketStatusSymbol})
+ }
+ }
+ processedPacketNum += packetNumberToProcess
+ case TypeTCCStatusVectorChunk:
+ packetStatus := &StatusVectorChunk{Type: typ}
+ iPacketStatus = packetStatus
+ err := packetStatus.Unmarshal(rawPacket[packetStatusPos : packetStatusPos+2])
+ if err != nil {
+ return err
+ }
+ if packetStatus.SymbolSize == TypeTCCSymbolSizeOneBit {
+ for j := 0; j < len(packetStatus.SymbolList); j++ {
+ if packetStatus.SymbolList[j] == TypeTCCPacketReceivedSmallDelta {
+ t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: TypeTCCPacketReceivedSmallDelta})
+ }
+ }
+ }
+ if packetStatus.SymbolSize == TypeTCCSymbolSizeTwoBit {
+ for j := 0; j < len(packetStatus.SymbolList); j++ {
+ if packetStatus.SymbolList[j] == TypeTCCPacketReceivedSmallDelta || packetStatus.SymbolList[j] == TypeTCCPacketReceivedLargeDelta {
+ t.RecvDeltas = append(t.RecvDeltas, &RecvDelta{Type: packetStatus.SymbolList[j]})
+ }
+ }
+ }
+ processedPacketNum += uint16(len(packetStatus.SymbolList))
+ }
+ packetStatusPos += packetStatusChunkLength
+ t.PacketChunks = append(t.PacketChunks, iPacketStatus)
+ }
+
+ recvDeltasPos := packetStatusPos
+ for _, delta := range t.RecvDeltas {
+ if recvDeltasPos >= totalLength {
+ return errPacketTooShort
+ }
+ if delta.Type == TypeTCCPacketReceivedSmallDelta {
+ err := delta.Unmarshal(rawPacket[recvDeltasPos : recvDeltasPos+1])
+ if err != nil {
+ return err
+ }
+ recvDeltasPos++
+ }
+ if delta.Type == TypeTCCPacketReceivedLargeDelta {
+ err := delta.Unmarshal(rawPacket[recvDeltasPos : recvDeltasPos+2])
+ if err != nil {
+ return err
+ }
+ recvDeltasPos += 2
+ }
+ }
+
+ return nil
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (t TransportLayerCC) DestinationSSRC() []uint32 {
+ return []uint32{t.MediaSSRC}
+}
+
+func min(x, y uint16) uint16 {
+ if x < y {
+ return x
+ }
+ return y
+}
diff --git a/vendor/github.com/pion/rtcp/transport_layer_nack.go b/vendor/github.com/pion/rtcp/transport_layer_nack.go
new file mode 100644
index 0000000..f7ab803
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/transport_layer_nack.go
@@ -0,0 +1,174 @@
+package rtcp
+
+import (
+ "encoding/binary"
+ "fmt"
+ "math"
+)
+
+// PacketBitmap shouldn't be used like a normal integral,
+// so it's type is masked here. Access it with PacketList().
+type PacketBitmap uint16
+
+// NackPair is a wire-representation of a collection of
+// Lost RTP packets
+type NackPair struct {
+ // ID of lost packets
+ PacketID uint16
+
+ // Bitmask of following lost packets
+ LostPackets PacketBitmap
+}
+
+// The TransportLayerNack packet informs the encoder about the loss of a transport packet
+// IETF RFC 4585, Section 6.2.1
+// https://tools.ietf.org/html/rfc4585#section-6.2.1
+type TransportLayerNack struct {
+ // SSRC of sender
+ SenderSSRC uint32
+
+ // SSRC of the media source
+ MediaSSRC uint32
+
+ Nacks []NackPair
+}
+
+var _ Packet = (*TransportLayerNack)(nil) // assert is a Packet
+
+// NackPairsFromSequenceNumbers generates a slice of NackPair from a list of SequenceNumbers
+// This handles generating the proper values for PacketID/LostPackets
+func NackPairsFromSequenceNumbers(sequenceNumbers []uint16) (pairs []NackPair) {
+ if len(sequenceNumbers) == 0 {
+ return []NackPair{}
+ }
+
+ nackPair := &NackPair{PacketID: sequenceNumbers[0]}
+ for i := 1; i < len(sequenceNumbers); i++ {
+ m := sequenceNumbers[i]
+
+ if m-nackPair.PacketID > 16 {
+ pairs = append(pairs, *nackPair)
+ nackPair = &NackPair{PacketID: m}
+ continue
+ }
+
+ nackPair.LostPackets |= 1 << (m - nackPair.PacketID - 1)
+ }
+ pairs = append(pairs, *nackPair)
+ return
+}
+
+// Range calls f sequentially for each sequence number covered by n.
+// If f returns false, Range stops the iteration.
+func (n *NackPair) Range(f func(seqno uint16) bool) {
+ more := f(n.PacketID)
+ if !more {
+ return
+ }
+
+ b := n.LostPackets
+ for i := uint16(0); b != 0; i++ {
+ if (b & (1 << i)) != 0 {
+ b &^= (1 << i)
+ more = f(n.PacketID + i + 1)
+ if !more {
+ return
+ }
+ }
+ }
+}
+
+// PacketList returns a list of Nack'd packets that's referenced by a NackPair
+func (n *NackPair) PacketList() []uint16 {
+ out := make([]uint16, 0, 17)
+ n.Range(func(seqno uint16) bool {
+ out = append(out, seqno)
+ return true
+ })
+ return out
+}
+
+const (
+ tlnLength = 2
+ nackOffset = 8
+)
+
+// Marshal encodes the TransportLayerNack in binary
+func (p TransportLayerNack) Marshal() ([]byte, error) {
+ if len(p.Nacks)+tlnLength > math.MaxUint8 {
+ return nil, errTooManyReports
+ }
+
+ rawPacket := make([]byte, nackOffset+(len(p.Nacks)*4))
+ binary.BigEndian.PutUint32(rawPacket, p.SenderSSRC)
+ binary.BigEndian.PutUint32(rawPacket[4:], p.MediaSSRC)
+ for i := 0; i < len(p.Nacks); i++ {
+ binary.BigEndian.PutUint16(rawPacket[nackOffset+(4*i):], p.Nacks[i].PacketID)
+ binary.BigEndian.PutUint16(rawPacket[nackOffset+(4*i)+2:], uint16(p.Nacks[i].LostPackets))
+ }
+ h := p.Header()
+ hData, err := h.Marshal()
+ if err != nil {
+ return nil, err
+ }
+
+ return append(hData, rawPacket...), nil
+}
+
+// Unmarshal decodes the TransportLayerNack from binary
+func (p *TransportLayerNack) Unmarshal(rawPacket []byte) error {
+ if len(rawPacket) < (headerLength + ssrcLength) {
+ return errPacketTooShort
+ }
+
+ var h Header
+ if err := h.Unmarshal(rawPacket); err != nil {
+ return err
+ }
+
+ if len(rawPacket) < (headerLength + int(4*h.Length)) {
+ return errPacketTooShort
+ }
+
+ if h.Type != TypeTransportSpecificFeedback || h.Count != FormatTLN {
+ return errWrongType
+ }
+
+ p.SenderSSRC = binary.BigEndian.Uint32(rawPacket[headerLength:])
+ p.MediaSSRC = binary.BigEndian.Uint32(rawPacket[headerLength+ssrcLength:])
+ for i := headerLength + nackOffset; i < (headerLength + int(h.Length*4)); i += 4 {
+ p.Nacks = append(p.Nacks, NackPair{
+ binary.BigEndian.Uint16(rawPacket[i:]),
+ PacketBitmap(binary.BigEndian.Uint16(rawPacket[i+2:])),
+ })
+ }
+ return nil
+}
+
+func (p *TransportLayerNack) len() int {
+ return headerLength + nackOffset + (len(p.Nacks) * 4)
+}
+
+// Header returns the Header associated with this packet.
+func (p *TransportLayerNack) Header() Header {
+ return Header{
+ Count: FormatTLN,
+ Type: TypeTransportSpecificFeedback,
+ Length: uint16((p.len() / 4) - 1),
+ }
+}
+
+func (p TransportLayerNack) String() string {
+ out := fmt.Sprintf("TransportLayerNack from %x\n", p.SenderSSRC)
+ out += fmt.Sprintf("\tMedia Ssrc %x\n", p.MediaSSRC)
+ out += "\tID\tLostPackets\n"
+ for _, i := range p.Nacks {
+ out += fmt.Sprintf("\t%d\t%b\n", i.PacketID, i.LostPackets)
+ }
+ return out
+}
+
+// DestinationSSRC returns an array of SSRC values that this packet refers to.
+func (p *TransportLayerNack) DestinationSSRC() []uint32 {
+ return []uint32{p.MediaSSRC}
+}
diff --git a/vendor/github.com/pion/rtcp/util.go b/vendor/github.com/pion/rtcp/util.go
new file mode 100644
index 0000000..5702d35
--- /dev/null
+++ b/vendor/github.com/pion/rtcp/util.go
@@ -0,0 +1,38 @@
+package rtcp
+
+// getPadding Returns the padding required to make the length a multiple of 4
+func getPadding(len int) int {
+ if len%4 == 0 {
+ return 0
+ }
+ return 4 - (len % 4)
+}
+
+// setNBitsOfUint16 will truncate the value to size, left-shift to startIndex position and set
+func setNBitsOfUint16(src, size, startIndex, val uint16) (uint16, error) {
+ if startIndex+size > 16 {
+ return 0, errInvalidSizeOrStartIndex
+ }
+
+ // truncate val to size bits
+ val &= (1 << size) - 1
+
+ return src | (val << (16 - size - startIndex)), nil
+}
+
+// appendBit32 will left-shift and append n bits of val
+func appendNBitsToUint32(src, n, val uint32) uint32 {
+ return (src << n) | (val & (0xFFFFFFFF >> (32 - n)))
+}
+
+// getNBit get n bits from 1 byte, begin with a position
+func getNBitsFromByte(b byte, begin, n uint16) uint16 {
+ endShift := 8 - (begin + n)
+ mask := (0xFF >> begin) & uint8(0xFF<<endShift)
+ return uint16(b&mask) >> endShift
+}
+
+// get24BitFromBytes get 24bits from `[3]byte` slice
+func get24BitsFromBytes(b []byte) uint32 {
+ return uint32(b[0])<<16 + uint32(b[1])<<8 + uint32(b[2])
+}