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