/* NAME rtcp.go DESCRIPTION rtcp.go contains structs to describe RTCP packets, and functionality to form []bytes of these structs. AUTHORS Saxon A. Nelson-Milton LICENSE This is Copyright (C) 2019 the Australian Ocean Lab (AusOcean) It is free software: you can redistribute it and/or modify them under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. It is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License in gpl.txt. If not, see http://www.gnu.org/licenses. */ 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 senderReportSize = 28 ) // 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(buf []byte) []byte { l := 8 + 4*reportBlockSize*len(r.Blocks) + 4*len(r.Extensions) if buf == nil || cap(buf) < l { buf = make([]byte, l) } buf = buf[: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) binary.BigEndian.PutUint32(buf[idx+4:], b.PacketsLost) buf[idx+4] = b.FractionLost binary.BigEndian.PutUint32(buf[idx+8:], b.HighestSequence) binary.BigEndian.PutUint32(buf[idx+12:], b.Jitter) binary.BigEndian.PutUint32(buf[idx+16:], b.LSR) binary.BigEndian.PutUint32(buf[idx+20:], b.DLSR) idx += 24 } 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(buf []byte) []byte { bodyLen := d.bodyLen() rem := bodyLen % 4 if rem != 0 { bodyLen += 4 - rem } l := 4 + bodyLen if buf == nil || cap(buf) < l { buf = make([]byte, l) } buf = buf[: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 buf[idx+1] = byte(len(i.Text)) idx += 2 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 { var l int for _, c := range d.Chunks { l += c.len() } return l } // SenderReport describes an RTCP sender report. type SenderReport struct { Header // Standard RTCP header. SSRC uint32 // SSRC of sender. TimestampMSW uint32 // Most significant word of timestamp. TimestampLSW uint32 // Least significant word of timestamp. RTPTimestamp uint32 // Current RTP timestamp. PacketCount uint32 // Senders packet count. OctetCount uint32 // Senders octet count. // Report blocks (unimplemented) // ... } // Bytes returns a []byte of the SenderReport. func (r *SenderReport) Bytes() []byte { buf := make([]byte, senderReportSize) r.writeHeader(buf, senderReportSize-1) for i, w := range []uint32{ r.SSRC, r.TimestampMSW, r.TimestampLSW, r.RTPTimestamp, r.PacketCount, r.OctetCount, } { binary.BigEndian.PutUint32(buf[i+4:], w) } return buf } // 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 }