mirror of
				https://github.com/ossrs/srs.git
				synced 2025-03-09 15:49:59 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			144 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
	
		
			4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
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
 | 
						|
	TypeExtendedReport            PacketType = 207 // RFC 3611
 | 
						|
 | 
						|
)
 | 
						|
 | 
						|
// 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
 | 
						|
	FormatCCFB uint8 = 11
 | 
						|
	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"
 | 
						|
	case TypeExtendedReport:
 | 
						|
		return "XR"
 | 
						|
	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
 | 
						|
}
 |