av/protocol/rtcp/rtcp.go

161 lines
3.9 KiB
Go

package rtcp
import (
"encoding/binary"
)
// RTCP packet types.
const (
typeSenderReport = 200
typeReceiverReport = 201
typeSourceDescription = 202
)
// SDES Item types.
const (
typeCName = 1
)
// MISC.
const (
reportBlockSize = 6
)
// ReceiverReport describes an RTCP receiver report packet.
type ReceiverReport struct {
Header // Standard RTCP packet header.
SenderSSRC uint32 // SSRC of the sender of this report.
Blocks []ReportBlock // Report blocks.
Extensions [][4]byte // Contains any extensions to the packet.
}
// Bytes returns a []byte of the ReceiverReport r.
func (r *ReceiverReport) Bytes() []byte {
l := 8 + 4*reportBlockSize*len(r.Blocks) + 4*len(r.Extensions)
buf := make([]byte, l)
l = 1 + reportBlockSize*len(r.Blocks) + len(r.Extensions)
r.writeHeader(buf, l)
binary.BigEndian.PutUint32(buf[4:], r.SenderSSRC)
idx := 8
for _, b := range r.Blocks {
binary.BigEndian.PutUint32(buf[idx:], b.SSRC)
idx += 4
binary.BigEndian.PutUint32(buf[idx:], b.PacketsLost)
buf[idx] = b.FractionLost
idx += 4
binary.BigEndian.PutUint32(buf[idx:], b.HighestSequence)
idx += 4
binary.BigEndian.PutUint32(buf[idx:], b.Jitter)
idx += 4
binary.BigEndian.PutUint32(buf[idx:], b.LSR)
idx += 4
binary.BigEndian.PutUint32(buf[idx:], b.DLSR)
idx += 4
}
for _, e := range r.Extensions {
copy(buf[idx:], e[:])
idx += 4
}
return buf
}
// ReportBlock describes an RTCP report block used in Sender/Receiver Reports.
type ReportBlock struct {
SSRC uint32 // Source identifier.
FractionLost uint8 // Fraction of packets lost.
PacketsLost uint32 // Cumulative number of packets lost.
HighestSequence uint32 // Extended highest sequence number received.
Jitter uint32 // Interarrival jitter.
LSR uint32 // Last sender report timestamp.
DLSR uint32 // Delay since last sender report.
}
// SourceDescription describes a source description RTCP packet.
type SourceDescription struct {
Header // Standard RTCP packet header.
Chunks []Chunk // Chunks to describe items of each SSRC.
}
// Bytes returns an []byte of the SourceDescription d.
func (d *SourceDescription) Bytes() []byte {
bodyLen := d.bodyLen()
rem := bodyLen % 4
if rem != 0 {
bodyLen += 4 - rem
}
l := 4 + bodyLen
buf := make([]byte, l)
d.writeHeader(buf, bodyLen/4)
idx := 4
for _, c := range d.Chunks {
binary.BigEndian.PutUint32(buf[idx:], c.SSRC)
idx += 4
for _, i := range c.Items {
buf[idx] = i.Type
idx++
buf[idx] = byte(len(i.Text))
idx++
copy(buf[idx:], i.Text)
idx += len(i.Text)
}
}
return buf
}
// bodyLen calculates the body length of a source description packet in bytes.
func (d *SourceDescription) bodyLen() int {
l := 0
for _, c := range d.Chunks {
l += c.len()
}
return l
}
// Header describes a standard RTCP packet header.
type Header struct {
Version uint8 // RTCP version.
Padding bool // Padding indicator.
ReportCount uint8 // Number of reports contained.
Type uint8 // Type of RTCP packet.
}
// SDESItem describes a source description item.
type SDESItem struct {
Type uint8 // Type of item.
Text []byte // Item text.
}
// Chunk describes a source description chunk for a given SSRC.
type Chunk struct {
SSRC uint32 // SSRC of the source being described by the below items.
Items []SDESItem // Items describing the source.
}
// len returns the len of a chunk in bytes.
func (c *Chunk) len() int {
tot := 4
for _, i := range c.Items {
tot += 2 + len(i.Text)
}
return tot
}
// writeHeader writes the standard RTCP header given a buffer to write to and l
// the RTCP body length that needs to be encoded into the header.
func (h Header) writeHeader(buf []byte, l int) {
buf[0] = h.Version<<6 | asByte(h.Padding)<<5 | 0x1f&h.ReportCount
buf[1] = h.Type
binary.BigEndian.PutUint16(buf[2:], uint16(l))
}
func asByte(b bool) byte {
if b {
return 0x01
}
return 0x00
}