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}