// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>// SPDX-License-Identifier: MITpackage rtcpimport ()// ReceiverEstimatedMaximumBitrate contains the receiver's estimated maximum bitrate.// see: https://tools.ietf.org/html/draft-alvestrand-rmcat-remb-03typeReceiverEstimatedMaximumBitratestruct {// SSRC of sender SenderSSRC uint32// Estimated maximum bitrate Bitrate float32// SSRC entries which this packet applies to SSRCs []uint32}// Marshal serializes the packet and returns a byte slice.func ( ReceiverEstimatedMaximumBitrate) () ( []byte, error) {// Allocate a buffer of the exact output size. = make([]byte, .MarshalSize())// Write to our buffer. , := .MarshalTo()if != nil {returnnil, }// This will always be true but just to be safe.if != len() {returnnil, errWrongMarshalSize }return , nil}// MarshalSize returns the size of the packet once marshaledfunc ( ReceiverEstimatedMaximumBitrate) () int {return20 + 4*len(.SSRCs)}// MarshalTo serializes the packet to the given byte slice.func ( ReceiverEstimatedMaximumBitrate) ( []byte) ( int, error) {const = 0x3FFFFp+63/* 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 | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | ... | */ := .MarshalSize()iflen() < {return0, errPacketTooShort } [0] = 143// v=2, p=0, fmt=15 [1] = 206// Length of this packet in 32-bit words minus one. := uint16((.MarshalSize() / 4) - 1)binary.BigEndian.PutUint16([2:4], )binary.BigEndian.PutUint32([4:8], .SenderSSRC)binary.BigEndian.PutUint32([8:12], 0) // always zero// ALL HAIL REMB [12] = 'R' [13] = 'E' [14] = 'M' [15] = 'B'// Write the length of the ssrcs to follow at the end [16] = byte(len(.SSRCs)) := 0 := .Bitrateif >= { = }if < 0 {return0, errInvalidBitrate }for >= (1 << 18) { /= 2.0 ++ }if >= (1 << 6) {return0, errInvalidBitrate } := uint(math.Floor(float64()))// 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. [17] = byte(<<2) | byte(>>16) [18] = byte( >> 8) [19] = byte()// Write the SSRCs at the very end. = 20for , := range .SSRCs {binary.BigEndian.PutUint32([:+4], ) += 4 }return , nil}// Unmarshal reads a REMB packet from the given byte slice.func ( *ReceiverEstimatedMaximumBitrate) ( []byte) ( error) {const = 0x7FFFFF/* 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 SSRCsiflen() < 20 {returnerrPacketTooShort }// version must be 2 := [0] >> 6if != 2 {returnfmt.Errorf("%w expected(2) actual(%d)", errBadVersion, ) }// padding must be unset := ([0] >> 5) & 1if != 0 {returnfmt.Errorf("%w expected(0) actual(%d)", errWrongPadding, ) }// fmt must be 15 := [0] & 31if != 15 {returnfmt.Errorf("%w expected(15) actual(%d)", errWrongFeedbackType, ) }// Must be payload specific feedbackif [1] != 206 {returnfmt.Errorf("%w expected(206) actual(%d)", errWrongPayloadType, [1]) }// length is the number of 32-bit words, minus 1 := binary.BigEndian.Uint16([2:4]) := int(( + 1) * 4)// There's not way this could be legitif < 20 {returnerrHeaderTooSmall }// Make sure the buffer is large enough.iflen() < {returnerrPacketTooShort }// The sender SSRC is 32-bits .SenderSSRC = binary.BigEndian.Uint32([4:8])// The destination SSRC must be 0 := binary.BigEndian.Uint32([8:12])if != 0 {returnerrSSRCMustBeZero }// REMB rules all around meif !bytes.Equal([12:16], []byte{'R', 'E', 'M', 'B'}) {returnerrMissingREMBidentifier }// The next byte is the number of SSRC entries at the end. := int([16])// Now we know the expected size, make sure they match.if != 20+4* {returnerrSSRCNumAndLengthMismatch }// Get the 6-bit exponent value. := [17] >> 2 += 127// bias for IEEE754 += 23// IEEE754 biases the decimal to the left, abs-send-time biases it to the right// The remaining 2-bits plus the next 16-bits are the mantissa. := uint32([17]&3)<<16 | uint32([18])<<8 | uint32([19])if != 0 {// ieee754 requires an implicit leading bitfor ( & ( + 1)) == 0 { -- *= 2 } }// bitrate = mantissa * 2^exp .Bitrate = math.Float32frombits((uint32() << 23) | ( & ))// Clear any existing SSRCs .SSRCs = nil// Loop over and parse the SSRC entires at the end. // We already verified that size == num * 4for := 20; < ; += 4 { := binary.BigEndian.Uint32([ : +4]) .SSRCs = append(.SSRCs, ) }returnnil}// Header returns the Header associated with this packet.func ( *ReceiverEstimatedMaximumBitrate) () Header {returnHeader{Count: FormatREMB,Type: TypePayloadSpecificFeedback,Length: uint16((.MarshalSize() / 4) - 1), }}// String prints the REMB packet in a human-readable format.func ( *ReceiverEstimatedMaximumBitrate) () string {// Keep a table of powers to units for fast conversion. := []string{"b", "Kb", "Mb", "Gb", "Tb", "Pb", "Eb"}// Do some unit conversions because b/s is far too difficult to read. := .Bitrate := 0// Keep dividing the bitrate until it's under 1000for >= 1000.0 && < len() { /= 1000.0 ++ } := []returnfmt.Sprintf("ReceiverEstimatedMaximumBitrate %x %.2f %s/s", .SenderSSRC, , )}// DestinationSSRC returns an array of SSRC values that this packet refers to.func ( *ReceiverEstimatedMaximumBitrate) () []uint32 {return .SSRCs}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.