diff options
Diffstat (limited to 'vendor/github.com/pion/rtcp/sender_report.go')
-rw-r--r-- | vendor/github.com/pion/rtcp/sender_report.go | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/vendor/github.com/pion/rtcp/sender_report.go b/vendor/github.com/pion/rtcp/sender_report.go new file mode 100644 index 0000000..1b16380 --- /dev/null +++ b/vendor/github.com/pion/rtcp/sender_report.go @@ -0,0 +1,260 @@ +package rtcp + +import ( + "encoding/binary" + "fmt" +) + +// A SenderReport (SR) packet provides reception quality feedback for an RTP stream +type SenderReport struct { + // The synchronization source identifier for the originator of this SR packet. + SSRC uint32 + // The wallclock time when this report was sent so that it may be used in + // combination with timestamps returned in reception reports from other + // receivers to measure round-trip propagation to those receivers. + NTPTime uint64 + // Corresponds to the same time as the NTP timestamp (above), but in + // the same units and with the same random offset as the RTP + // timestamps in data packets. This correspondence may be used for + // intra- and inter-media synchronization for sources whose NTP + // timestamps are synchronized, and may be used by media-independent + // receivers to estimate the nominal RTP clock frequency. + RTPTime uint32 + // The total number of RTP data packets transmitted by the sender + // since starting transmission up until the time this SR packet was + // generated. + PacketCount uint32 + // The total number of payload octets (i.e., not including header or + // padding) transmitted in RTP data packets by the sender since + // starting transmission up until the time this SR packet was + // generated. + OctetCount uint32 + // Zero or more reception report blocks depending on the number of other + // sources heard by this sender since the last report. Each reception report + // block conveys statistics on the reception of RTP packets from a + // single synchronization source. + Reports []ReceptionReport + // ProfileExtensions contains additional, payload-specific information that needs to + // be reported regularly about the sender. + ProfileExtensions []byte +} + +var _ Packet = (*SenderReport)(nil) // assert is a Packet + +const ( + srHeaderLength = 24 + srSSRCOffset = 0 + srNTPOffset = srSSRCOffset + ssrcLength + ntpTimeLength = 8 + srRTPOffset = srNTPOffset + ntpTimeLength + rtpTimeLength = 4 + srPacketCountOffset = srRTPOffset + rtpTimeLength + srPacketCountLength = 4 + srOctetCountOffset = srPacketCountOffset + srPacketCountLength + srOctetCountLength = 4 + srReportOffset = srOctetCountOffset + srOctetCountLength +) + +// Marshal encodes the SenderReport in binary +func (r SenderReport) 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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * header |V=2|P| RC | PT=SR=200 | length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SSRC of sender | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * sender | NTP timestamp, most significant word | + * info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NTP timestamp, least significant word | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RTP timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | sender's packet count | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | sender's octet count | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * report | SSRC_1 (SSRC of first source) | + * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 1 | fraction lost | cumulative number of packets lost | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | extended highest sequence number received | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | interarrival jitter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | last SR (LSR) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | delay since last SR (DLSR) | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * report | SSRC_2 (SSRC of second source) | + * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 2 : ... : + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * | profile-specific extensions | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + rawPacket := make([]byte, r.len()) + packetBody := rawPacket[headerLength:] + + binary.BigEndian.PutUint32(packetBody[srSSRCOffset:], r.SSRC) + binary.BigEndian.PutUint64(packetBody[srNTPOffset:], r.NTPTime) + binary.BigEndian.PutUint32(packetBody[srRTPOffset:], r.RTPTime) + binary.BigEndian.PutUint32(packetBody[srPacketCountOffset:], r.PacketCount) + binary.BigEndian.PutUint32(packetBody[srOctetCountOffset:], r.OctetCount) + + offset := srHeaderLength + for _, rp := range r.Reports { + data, err := rp.Marshal() + if err != nil { + return nil, err + } + copy(packetBody[offset:], data) + offset += receptionReportLength + } + + if len(r.Reports) > countMax { + return nil, errTooManyReports + } + + copy(packetBody[offset:], r.ProfileExtensions) + + hData, err := r.Header().Marshal() + if err != nil { + return nil, err + } + copy(rawPacket, hData) + + return rawPacket, nil +} + +// Unmarshal decodes the SenderReport from binary +func (r *SenderReport) Unmarshal(rawPacket []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 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * header |V=2|P| RC | PT=SR=200 | length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SSRC of sender | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * sender | NTP timestamp, most significant word | + * info +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | NTP timestamp, least significant word | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | RTP timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | sender's packet count | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | sender's octet count | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * report | SSRC_1 (SSRC of first source) | + * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 1 | fraction lost | cumulative number of packets lost | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | extended highest sequence number received | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | interarrival jitter | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | last SR (LSR) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | delay since last SR (DLSR) | + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * report | SSRC_2 (SSRC of second source) | + * block +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * 2 : ... : + * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ + * | profile-specific extensions | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + + if len(rawPacket) < (headerLength + srHeaderLength) { + return errPacketTooShort + } + + var h Header + if err := h.Unmarshal(rawPacket); err != nil { + return err + } + + if h.Type != TypeSenderReport { + return errWrongType + } + + packetBody := rawPacket[headerLength:] + + r.SSRC = binary.BigEndian.Uint32(packetBody[srSSRCOffset:]) + r.NTPTime = binary.BigEndian.Uint64(packetBody[srNTPOffset:]) + r.RTPTime = binary.BigEndian.Uint32(packetBody[srRTPOffset:]) + r.PacketCount = binary.BigEndian.Uint32(packetBody[srPacketCountOffset:]) + r.OctetCount = binary.BigEndian.Uint32(packetBody[srOctetCountOffset:]) + + offset := srReportOffset + for i := 0; i < int(h.Count); i++ { + rrEnd := offset + receptionReportLength + if rrEnd > len(packetBody) { + return errPacketTooShort + } + rrBody := packetBody[offset : offset+receptionReportLength] + offset = rrEnd + + var rr ReceptionReport + if err := rr.Unmarshal(rrBody); err != nil { + return err + } + r.Reports = append(r.Reports, rr) + } + + if offset < len(packetBody) { + r.ProfileExtensions = packetBody[offset:] + } + + if uint8(len(r.Reports)) != h.Count { + return errInvalidHeader + } + + return nil +} + +// DestinationSSRC returns an array of SSRC values that this packet refers to. +func (r *SenderReport) DestinationSSRC() []uint32 { + out := make([]uint32, len(r.Reports)+1) + for i, v := range r.Reports { + out[i] = v.SSRC + } + out[len(r.Reports)] = r.SSRC + return out +} + +func (r *SenderReport) len() int { + repsLength := 0 + for _, rep := range r.Reports { + repsLength += rep.len() + } + return headerLength + srHeaderLength + repsLength + len(r.ProfileExtensions) +} + +// Header returns the Header associated with this packet. +func (r *SenderReport) Header() Header { + return Header{ + Count: uint8(len(r.Reports)), + Type: TypeSenderReport, + Length: uint16((r.len() / 4) - 1), + } +} + +func (r SenderReport) String() string { + out := fmt.Sprintf("SenderReport from %x\n", r.SSRC) + out += fmt.Sprintf("\tNTPTime:\t%d\n", r.NTPTime) + out += fmt.Sprintf("\tRTPTIme:\t%d\n", r.RTPTime) + out += fmt.Sprintf("\tPacketCount:\t%d\n", r.PacketCount) + out += fmt.Sprintf("\tOctetCount:\t%d\n", r.OctetCount) + + out += "\tSSRC \tLost\tLastSequence\n" + for _, i := range r.Reports { + out += fmt.Sprintf("\t%x\t%d/%d\t%d\n", i.SSRC, i.FractionLost, i.TotalLost, i.LastSequenceNumber) + } + out += fmt.Sprintf("\tProfile Extension Data: %v\n", r.ProfileExtensions) + return out +} |