package rtcp import ( "encoding/binary" ) // RTCP packet types. const ( typeSenderReport = 200 typeReceiverReport = 201 typeSourceDescription = 202 ) // SDES Item types. const ( typeCName = 1 ) const ( reportBlockSize = 6 ) type ReceiverReport struct { Header SenderSSRC uint32 Blocks []ReportBlock Extensions [][4]byte } 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 } 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. } type SourceDescription struct { Header Chunks []Chunk } 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 } func (d *SourceDescription) bodyLen() int { l := 0 for _, c := range d.Chunks { l += c.len() } return l } type Header struct { Version uint8 // RTCP version. Padding bool // Padding indicator. ReportCount uint8 // Number of reports contained. Type uint8 // Type of RTCP packet. } type SDESItem struct { Type uint8 Text []byte } type Chunk struct { SSRC uint32 Items []SDESItem } func (c *Chunk) len() int { tot := 4 for _, i := range c.Items { tot += 2 + len(i.Text) } return tot } 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 }