Skip to main content

rtc_rtcp/sender_report/
mod.rs

1#[cfg(test)]
2mod sender_report_test;
3
4use crate::{header::*, packet::*, reception_report::*, util::*};
5use shared::{
6    error::{Error, Result},
7    marshal::{Marshal, MarshalSize, Unmarshal},
8};
9
10use bytes::{Buf, BufMut, Bytes};
11use std::any::Any;
12use std::fmt;
13
14pub(crate) const SR_HEADER_LENGTH: usize = 24;
15pub(crate) const SR_SSRC_OFFSET: usize = HEADER_LENGTH;
16pub(crate) const SR_REPORT_OFFSET: usize = SR_SSRC_OFFSET + SR_HEADER_LENGTH;
17
18pub(crate) const SR_NTP_OFFSET: usize = SR_SSRC_OFFSET + SSRC_LENGTH;
19pub(crate) const NTP_TIME_LENGTH: usize = 8;
20pub(crate) const SR_RTP_OFFSET: usize = SR_NTP_OFFSET + NTP_TIME_LENGTH;
21pub(crate) const RTP_TIME_LENGTH: usize = 4;
22pub(crate) const SR_PACKET_COUNT_OFFSET: usize = SR_RTP_OFFSET + RTP_TIME_LENGTH;
23pub(crate) const SR_PACKET_COUNT_LENGTH: usize = 4;
24pub(crate) const SR_OCTET_COUNT_OFFSET: usize = SR_PACKET_COUNT_OFFSET + SR_PACKET_COUNT_LENGTH;
25pub(crate) const SR_OCTET_COUNT_LENGTH: usize = 4;
26
27/// A SenderReport (SR) packet provides reception quality feedback for an RTP stream
28#[derive(Debug, PartialEq, Eq, Default, Clone)]
29pub struct SenderReport {
30    /// The synchronization source identifier for the originator of this SR packet.
31    pub ssrc: u32,
32    /// The wallclock time when this report was sent so that it may be used in
33    /// combination with timestamps returned in reception reports from other
34    /// receivers to measure round-trip propagation to those receivers.
35    pub ntp_time: u64,
36    /// Corresponds to the same time as the NTP timestamp (above), but in
37    /// the same units and with the same random offset as the RTP
38    /// timestamps in data packets. This correspondence may be used for
39    /// intra- and inter-media synchronization for sources whose NTP
40    /// timestamps are synchronized, and may be used by media-independent
41    /// receivers to estimate the nominal RTP clock frequency.
42    pub rtp_time: u32,
43    /// The total number of RTP data packets transmitted by the sender
44    /// since starting transmission up until the time this SR packet was
45    /// generated.
46    pub packet_count: u32,
47    /// The total number of payload octets (i.e., not including header or
48    /// padding) transmitted in RTP data packets by the sender since
49    /// starting transmission up until the time this SR packet was
50    /// generated.
51    pub octet_count: u32,
52    /// Zero or more reception report blocks depending on the number of other
53    /// sources heard by this sender since the last report. Each reception report
54    /// block conveys statistics on the reception of RTP packets from a
55    /// single synchronization source.
56    pub reports: Vec<ReceptionReport>,
57
58    /// ProfileExtensions contains additional, payload-specific information that needs to
59    /// be reported regularly about the sender.
60    pub profile_extensions: Bytes,
61}
62
63impl fmt::Display for SenderReport {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        let mut out = format!("SenderReport from {}\n", self.ssrc);
66        out += format!("\tNTPTime:\t{}\n", self.ntp_time).as_str();
67        out += format!("\tRTPTIme:\t{}\n", self.rtp_time).as_str();
68        out += format!("\tPacketCount:\t{}\n", self.packet_count).as_str();
69        out += format!("\tOctetCount:\t{}\n", self.octet_count).as_str();
70        out += "\tSSRC    \tLost\tLastSequence\n";
71        for rep in &self.reports {
72            out += format!(
73                "\t{:x}\t{}/{}\t{}\n",
74                rep.ssrc, rep.fraction_lost, rep.total_lost, rep.last_sequence_number
75            )
76            .as_str();
77        }
78        out += format!("\tProfile Extension Data: {:?}\n", self.profile_extensions).as_str();
79
80        write!(f, "{out}")
81    }
82}
83
84impl Packet for SenderReport {
85    /// Header returns the Header associated with this packet.
86    fn header(&self) -> Header {
87        Header {
88            padding: get_padding_size(self.raw_size()) != 0,
89            count: self.reports.len() as u8,
90            packet_type: PacketType::SenderReport,
91            length: ((self.marshal_size() / 4) - 1) as u16,
92        }
93    }
94
95    /// destination_ssrc returns an array of SSRC values that this packet refers to.
96    fn destination_ssrc(&self) -> Vec<u32> {
97        let mut out: Vec<u32> = self.reports.iter().map(|x| x.ssrc).collect();
98        out.push(self.ssrc);
99        out
100    }
101
102    fn raw_size(&self) -> usize {
103        let mut reps_length = 0;
104        for rep in &self.reports {
105            reps_length += rep.marshal_size();
106        }
107
108        HEADER_LENGTH + SR_HEADER_LENGTH + reps_length + self.profile_extensions.len()
109    }
110
111    fn as_any(&self) -> &dyn Any {
112        self
113    }
114
115    fn equal(&self, other: &dyn Packet) -> bool {
116        other.as_any().downcast_ref::<SenderReport>() == Some(self)
117    }
118
119    fn cloned(&self) -> Box<dyn Packet> {
120        Box::new(self.clone())
121    }
122}
123
124impl MarshalSize for SenderReport {
125    fn marshal_size(&self) -> usize {
126        let l = self.raw_size();
127        // align to 32-bit boundary
128        l + get_padding_size(l)
129    }
130}
131
132impl Marshal for SenderReport {
133    /// Marshal encodes the packet in binary.
134    fn marshal_to(&self, mut buf: &mut [u8]) -> Result<usize> {
135        if self.reports.len() > COUNT_MAX {
136            return Err(Error::TooManyReports);
137        }
138
139        if buf.remaining_mut() < self.marshal_size() {
140            return Err(Error::BufferTooShort);
141        }
142
143        /*
144         *         0                   1                   2                   3
145         *         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
146         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
147         * header |V=2|P|    RC   |   PT=SR=200   |             length            |
148         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
149         *        |                         SSRC of sender                        |
150         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
151         * sender |              NTP timestamp, most significant word             |
152         * info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
153         *        |             NTP timestamp, least significant word             |
154         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
155         *        |                         RTP timestamp                         |
156         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
157         *        |                     sender's packet count                     |
158         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
159         *        |                      sender's octet count                     |
160         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
161         * report |                 SSRC_1 (SSRC of first source)                 |
162         * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
163         *   1    | fraction lost |       cumulative number of packets lost       |
164         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165         *        |           extended highest sequence number received           |
166         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167         *        |                      interarrival jitter                      |
168         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
169         *        |                         last SR (LSR)                         |
170         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171         *        |                   delay since last SR (DLSR)                  |
172         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
173         * report |                 SSRC_2 (SSRC of second source)                |
174         * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175         *   2    :                               ...                             :
176         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
177         *        |                  profile-specific extensions                  |
178         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179         */
180        let h = self.header();
181        let n = h.marshal_to(buf)?;
182        buf = &mut buf[n..];
183
184        buf.put_u32(self.ssrc);
185        buf.put_u64(self.ntp_time);
186        buf.put_u32(self.rtp_time);
187        buf.put_u32(self.packet_count);
188        buf.put_u32(self.octet_count);
189
190        for report in &self.reports {
191            let n = report.marshal_to(buf)?;
192            buf = &mut buf[n..];
193        }
194
195        buf.put(self.profile_extensions.clone());
196
197        if h.padding {
198            put_padding(buf, self.raw_size());
199        }
200
201        Ok(self.marshal_size())
202    }
203}
204
205impl Unmarshal for SenderReport {
206    /// Unmarshal decodes the SenderReport from binary
207    fn unmarshal<B>(raw_packet: &mut B) -> Result<Self>
208    where
209        Self: Sized,
210        B: Buf,
211    {
212        /*
213         *         0                   1                   2                   3
214         *         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
215         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216         * header |V=2|P|    RC   |   PT=SR=200   |             length            |
217         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
218         *        |                         SSRC of sender                        |
219         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
220         * sender |              NTP timestamp, most significant word             |
221         * info   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
222         *        |             NTP timestamp, least significant word             |
223         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
224         *        |                         RTP timestamp                         |
225         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
226         *        |                     sender's packet count                     |
227         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228         *        |                      sender's octet count                     |
229         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
230         * report |                 SSRC_1 (SSRC of first source)                 |
231         * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
232         *   1    | fraction lost |       cumulative number of packets lost       |
233         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234         *        |           extended highest sequence number received           |
235         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
236         *        |                      interarrival jitter                      |
237         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
238         *        |                         last SR (LSR)                         |
239         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240         *        |                   delay since last SR (DLSR)                  |
241         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
242         * report |                 SSRC_2 (SSRC of second source)                |
243         * block  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
244         *   2    :                               ...                             :
245         *        +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
246         *        |                  profile-specific extensions                  |
247         *        +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
248         */
249        let raw_packet_len = raw_packet.remaining();
250        if raw_packet_len < (HEADER_LENGTH + SR_HEADER_LENGTH) {
251            return Err(Error::PacketTooShort);
252        }
253
254        let header = Header::unmarshal(raw_packet)?;
255        if header.packet_type != PacketType::SenderReport {
256            return Err(Error::WrongType);
257        }
258
259        let ssrc = raw_packet.get_u32();
260        let ntp_time = raw_packet.get_u64();
261        let rtp_time = raw_packet.get_u32();
262        let packet_count = raw_packet.get_u32();
263        let octet_count = raw_packet.get_u32();
264
265        let mut offset = SR_REPORT_OFFSET;
266        let mut reports = Vec::with_capacity(header.count as usize);
267        for _ in 0..header.count {
268            if offset + RECEPTION_REPORT_LENGTH > raw_packet_len {
269                return Err(Error::PacketTooShort);
270            }
271            let reception_report = ReceptionReport::unmarshal(raw_packet)?;
272            reports.push(reception_report);
273            offset += RECEPTION_REPORT_LENGTH;
274        }
275        let profile_extensions = raw_packet.copy_to_bytes(raw_packet.remaining());
276        /*
277        if header.padding && raw_packet.has_remaining() {
278            raw_packet.advance(raw_packet.remaining());
279        }
280         */
281
282        Ok(SenderReport {
283            ssrc,
284            ntp_time,
285            rtp_time,
286            packet_count,
287            octet_count,
288            reports,
289            profile_extensions,
290        })
291    }
292}