webrtc-rtcp 0.2.0

A pure Rust implementation of RTCP
Documentation
use crate::errors::Error;

use byteorder::{BigEndian, ByteOrder};
use bytes::BytesMut;

/// A ReceptionReport block conveys statistics on the reception of RTP packets
/// from a single synchronization source.
#[derive(Debug, PartialEq, Default, Clone)]
pub struct ReceptionReport {
    /// The SSRC identifier of the source to which the information in this
    /// reception report block pertains.
    pub ssrc: u32,
    /// The fraction of RTP data packets from source SSRC lost since the
    /// previous SR or RR packet was sent, expressed as a fixed point
    /// number with the binary point at the left edge of the field.
    pub fraction_lost: u8,
    /// The total number of RTP data packets from source SSRC that have
    /// been lost since the beginning of reception.
    pub total_lost: u32,
    /// The low 16 bits contain the highest sequence number received in an
    /// RTP data packet from source SSRC, and the most significant 16
    /// bits extend that sequence number with the corresponding count of
    /// sequence number cycles.
    pub last_sequence_number: u32,
    /// An estimate of the statistical variance of the RTP data packet
    /// interarrival time, measured in timestamp units and expressed as an
    /// unsigned integer.
    pub jitter: u32,
    /// The middle 32 bits out of 64 in the NTP timestamp received as part of
    /// the most recent RTCP sender report (SR) packet from source SSRC. If no
    /// SR has been received yet, the field is set to zero.
    pub last_sender_report: u32,
    /// The delay, expressed in units of 1/65536 seconds, between receiving the
    /// last SR packet from source SSRC and sending this reception report block.
    /// If no SR packet has been received yet from SSRC, the field is set to zero.
    pub delay: u32,
}

#[allow(clippy::len_without_is_empty)]
impl ReceptionReport {
    pub fn len(&self) -> usize {
        super::RECEPTION_REPORT_LENGTH
    }

    /// Marshal encodes the ReceptionReport in binary
    pub fn marshal(&self) -> Result<BytesMut, 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
         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
         * |                              SSRC                             |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * | fraction lost |       cumulative number of packets lost       |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |           extended highest sequence number received           |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                      interarrival jitter                      |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                         last SR (LSR)                         |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                   delay since last SR (DLSR)                  |
         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
         */

        let mut raw_packet = vec![0u8; super::RECEPTION_REPORT_LENGTH];

        BigEndian::write_u32(&mut raw_packet, self.ssrc);

        raw_packet[super::FRACTION_LOST_OFFSET as usize] = self.fraction_lost;

        // pack TotalLost into 24 bits
        if self.total_lost >= (1 << 25) {
            return Err(Error::InvalidTotalLost);
        }

        let tl_bytes = &mut raw_packet[super::TOTAL_LOST_OFFSET..];
        tl_bytes[0] = (self.total_lost >> 16) as u8;
        tl_bytes[1] = (self.total_lost >> 8) as u8;
        tl_bytes[2] = (self.total_lost) as u8;

        BigEndian::write_u32(
            &mut raw_packet[super::LAST_SEQ_OFFSET..],
            self.last_sequence_number,
        );

        BigEndian::write_u32(&mut raw_packet[super::JITTER_OFFSET..], self.jitter);

        BigEndian::write_u32(
            &mut raw_packet[super::LAST_SR_OFFSET..],
            self.last_sender_report,
        );

        BigEndian::write_u32(&mut raw_packet[super::DELAY_OFFSET..], self.delay);

        Ok(raw_packet[..].into())
    }

    /// Unmarshal decodes the ReceptionReport from binary
    pub fn unmarshal(&mut self, raw_packet: &mut BytesMut) -> Result<(), Error> {
        if raw_packet.len() < super::RECEPTION_REPORT_LENGTH {
            return Err(Error::PacketTooShort);
        }

        /*
         *  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
         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
         * |                              SSRC                             |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * | fraction lost |       cumulative number of packets lost       |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |           extended highest sequence number received           |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                      interarrival jitter                      |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                         last SR (LSR)                         |
         * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
         * |                   delay since last SR (DLSR)                  |
         * +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
         */

        self.ssrc = BigEndian::read_u32(raw_packet);
        self.fraction_lost = raw_packet[super::FRACTION_LOST_OFFSET];

        let tl_bytes = &mut raw_packet[super::TOTAL_LOST_OFFSET..];
        self.total_lost =
            (tl_bytes[2] as u32) | (tl_bytes[1] as u32) << 8 | (tl_bytes[0] as u32) << 16;

        self.last_sequence_number = BigEndian::read_u32(&raw_packet[super::LAST_SEQ_OFFSET..]);
        self.jitter = BigEndian::read_u32(&raw_packet[super::JITTER_OFFSET..]);
        self.last_sender_report = BigEndian::read_u32(&raw_packet[super::LAST_SR_OFFSET..]);
        self.delay = BigEndian::read_u32(&raw_packet[super::DELAY_OFFSET..]);

        Ok(())
    }
}