Skip to content
File

Blob: firmware/vendor/str0m/src/streams/register.rs

rust427 lines
1use std::time::Instant;
2 
3use crate::rtp_::{Nack, ReceptionReport, SeqNo};
4 
5use super::register_nack::NackRegister;
6 
7#[derive(Debug)]
8pub struct ReceiverRegister {
9 nack: NackRegister,
10 
11 /// First sequence number received
12 first: Option<SeqNo>,
13 
14 /// Number of packets received
15 count: u64,
16 
17 /// Previously received time point.
18 time_point_prior: Option<TimePoint>,
19 
20 /// Expected at last reception report generation.
21 expected_prior: i64,
22 
23 /// Received at last reception report generation.
24 received_prior: i64,
25 
26 /// Interarrival jitter in **microseconds**.
27 ///
28 /// RTCP carries jitter in **RTP timestamp units** so use
29 /// [`ReceiverRegister::jitter_in_rtp_ts`] for the wire value.
30 jitter: f32,
31}
32 
33#[derive(Debug, Clone, Copy)]
34struct TimePoint {
35 arrival: Instant,
36 rtp_time: u32,
37 clock_rate: u32,
38}
39 
40impl TimePoint {
41 fn is_same(&self, other: TimePoint) -> bool {
42 self.rtp_time == other.rtp_time
43 }
44 
45 fn delta(&self, other: TimePoint) -> f32 {
46 // See
47 // https://www.rfc-editor.org/rfc/rfc3550#appendix-A.8
48 //
49 // rdur is often i 90kHz (for video) or 48kHz (for audio). we need
50 // a time unit of Duration, that is likely to give us an increase between
51 // 1 in rdur. milliseconds is thus "too coarse"
52 
53 // wrapping_sub to handle RTP time rollover
54 let rtp_diff = self.rtp_time.wrapping_sub(other.rtp_time) as i32;
55 let rdur = rtp_diff as f32 * 1_000_000.0 / self.clock_rate as f32;
56 
57 let tdur = (self.arrival - other.arrival).as_micros() as f32;
58 
59 let d = (tdur - rdur).abs();
60 
61 trace!("Timepoint delta: {}", d);
62 
63 d
64 }
65}
66 
67impl ReceiverRegister {
68 pub fn new(max_seq_no: Option<SeqNo>) -> Self {
69 ReceiverRegister {
70 nack: NackRegister::new(max_seq_no),
71 first: None,
72 count: 0,
73 time_point_prior: None,
74 expected_prior: 0,
75 received_prior: 0,
76 jitter: 0.0,
77 }
78 }
79 
80 pub fn accepts(&self, seq: SeqNo) -> bool {
81 self.nack.accepts(seq)
82 }
83 
84 pub fn update(&mut self, seq: SeqNo, arrival: Instant, rtp_time: u32, clock_rate: u32) -> bool {
85 if self.first.is_none() {
86 self.first = Some(seq);
87 }
88 
89 let new = self.nack.update(seq);
90 
91 if new {
92 self.count += 1;
93 }
94 
95 self.update_time(arrival, rtp_time, clock_rate);
96 
97 new
98 }
99 
100 /// Generates a NACK report
101 pub fn nack_report(&mut self) -> Option<impl Iterator<Item = Nack>> {
102 self.nack.nack_reports()
103 }
104 
105 /// Create a new reception report.
106 ///
107 /// This modifies the state since fraction_lost is calculated
108 /// since the last call to this function.
109 pub fn reception_report(&mut self) -> Option<ReceptionReport> {
110 let first = self.first?;
111 let last = self.max_seq()?;
112 
113 let expected = expected(first, last);
114 
115 Some(ReceptionReport {
116 ssrc: 0.into(),
117 fraction_lost: self.fraction_lost(expected, self.count as i64),
118 packets_lost: packets_lost(expected, self.count as i64),
119 max_seq: (*last % ((u32::MAX as u64) + 1_u64)) as u32,
120 jitter: self.jitter_in_rtp_ts(),
121 last_sr_time: 0,
122 last_sr_delay: 0,
123 })
124 }
125 
126 pub fn max_seq(&self) -> Option<SeqNo> {
127 self.nack.max_seq()
128 }
129 
130 pub fn clear(&mut self, max_seq_no: Option<SeqNo>) {
131 self.nack = NackRegister::new(max_seq_no);
132 self.count = 0;
133 self.first = None;
134 self.time_point_prior = None;
135 self.expected_prior = 0;
136 self.received_prior = 0;
137 self.jitter = 0.0;
138 }
139 
140 fn update_time(&mut self, arrival: Instant, rtp_time: u32, clock_rate: u32) {
141 let tp = TimePoint {
142 arrival,
143 rtp_time,
144 clock_rate,
145 };
146 
147 if let Some(prior) = self.time_point_prior {
148 if tp.is_same(prior) {
149 // rtp_time didn't move forward. this is quite normal
150 // when multiple rtp packets are needed for one keyframe.
151 
152 // https://www.cs.columbia.edu/~hgs/rtp/faq.html#jitter
153 //
154 // If several packets, say, within a video frame, bear the
155 // same timestamp, it is advisable to only use the first
156 // packet in a frame to compute the jitter. (This issue may
157 // be addressed in a future version of the specification.)
158 // Jitter is computed in timestamp units. For example, for
159 // an audio stream sampled at 8,000 Hz, the arrival time
160 // measured with the local clock is converted by multiplying
161 // the seconds by 8,000.
162 //
163 // Steve Casner wrote:
164 //
165 // For encodings such as MPEG that transmit data in a
166 // different order than it was sampled, this adds noise
167 // into the jitter calculation. I have heard handwavy
168 // arguments that this factor can be calculated out given
169 // that you know the shape of the noise, but my math
170 // isn't strong enough for that.
171 //
172 // In many of the cases that we care about, the jitter
173 // introduced by MPEG will be small enough that when the
174 // network jitter is of the same order we don't have a
175 // problem anyway.
176 //
177 // There is another problem for video in that all of the
178 // packets of a frame have the same timestamp because the
179 // whole frame is sampled at once. However, the
180 // dispersion in time of those packets really is all part
181 // of the network transfer process that the receiver must
182 // accommodate with its buffer.
183 //
184 // It has been suggested that jitter be calculated only
185 // on the first packet of a video frame, or only on "I"
186 // frames for MPEG. However, that may color the results
187 // also because those packets may see transit delays
188 // different than the following packets see.
189 //
190 // The main point to remember is that the primary
191 // function of the RTP timestamp is to represent the
192 // inherent notion of real time associated with the
193 // media. It also turns out to be useful for the jitter
194 // measure, but that is a secondary function.
195 //
196 // The jitter value is not expected to be useful as an
197 // absolute value. It is more useful as a means of
198 // comparing the reception quality at two receiver or
199 // comparing the reception quality 5 minutes ago to now.
200 
201 return;
202 }
203 
204 // update jitter.
205 let d = tp.delta(prior);
206 
207 self.jitter += (1.0 / 16.0) * (d - self.jitter);
208 }
209 
210 self.time_point_prior = Some(tp);
211 }
212 
213 // Calculations from here
214 // https://www.rfc-editor.org/rfc/rfc3550#appendix-A.3
215 
216 /// Fraction lost since last call.
217 fn fraction_lost(&mut self, expected: i64, received: i64) -> u8 {
218 let expected_interval = expected - self.expected_prior;
219 self.expected_prior = expected;
220 
221 let received_interval = received - self.received_prior;
222 self.received_prior = received;
223 
224 let lost_interval = expected_interval - received_interval;
225 
226 let lost = if expected_interval == 0 || lost_interval == 0 {
227 0
228 } else {
229 (lost_interval << 8) / expected_interval
230 } as u8;
231 
232 trace!("Reception fraction lost: {}", lost);
233 
234 lost
235 }
236 
237 /// Jitter in RTP timestamp units.
238 fn jitter_in_rtp_ts(&self) -> u32 {
239 let Some(sample_rate) = self.time_point_prior.map(|tp| tp.clock_rate) else {
240 return 0;
241 };
242 (self.jitter / 1_000_000.0 * sample_rate as f32).round() as u32
243 }
244}
245 
246/// Absolute number of lost packets.
247fn packets_lost(expected: i64, received: i64) -> u32 {
248 // Since this signed number is carried in 24 bits, it should be clamped
249 // at 0x7fffff for positive loss or 0x800000 for negative loss rather
250 // than wrapping around.
251 let lost_t = expected - received;
252 if lost_t > 0x7fffff {
253 0x7fffff_u32
254 } else if lost_t < -0x7fffff {
255 0x8000000_u32
256 } else {
257 lost_t as u32
258 }
259}
260 
261fn expected(first: SeqNo, last: SeqNo) -> i64 {
262 let delta = (*last - *first) as i64;
263 delta.saturating_add(1)
264}
265 
266#[cfg(test)]
267mod test {
268 use std::time::{Duration, Instant};
269 
270 use crate::streams::register::{ReceiverRegister, expected, packets_lost};
271 
272 #[test]
273 fn jitter_at_0() {
274 let mut r = ReceiverRegister::new(None);
275 
276 // 100 fps in clock rate 90kHz => 90_000/100 = 900 per frame
277 // 1/100 * 1_000_000 = 10_000 microseconds per frame.
278 
279 let start = Instant::now();
280 let dur = Duration::from_micros(10_000);
281 
282 r.update_time(start + 4 * dur, 1234 + 4 * 900, 90_000);
283 r.update_time(start + 5 * dur, 1234 + 5 * 900, 90_000);
284 r.update_time(start + 6 * dur, 1234 + 6 * 900, 90_000);
285 r.update_time(start + 7 * dur, 1234 + 7 * 900, 90_000);
286 assert_eq!(r.jitter, 0.0);
287 }
288 
289 #[test]
290 fn jitter_at_20() {
291 let mut r = ReceiverRegister::new(None);
292 
293 // 100 fps in clock rate 90kHz => 90_000/100 = 900 per frame
294 // 1/100 * 1_000_000 = 10_000 microseconds per frame.
295 
296 let start = Instant::now();
297 let dur = Duration::from_micros(10_000);
298 let off = Duration::from_micros(10);
299 
300 for i in 4..1000 {
301 let arrival = if i % 2 == 0 {
302 start + (i * dur).checked_sub(off).unwrap()
303 } else {
304 start + i * dur + off
305 };
306 r.update((i as u64).into(), arrival, 1234 + i * 900, 90_000);
307 }
308 
309 // jitter should converge on 20.0
310 assert!(
311 (20.0 - r.jitter).abs() < 0.01,
312 "Expected jitter to converge at 20.0, jitter was: {}",
313 r.jitter
314 );
315 
316 // jitter is also present in reception report
317 let report = r.reception_report().expect("some report");
318 // 90kHz is 11.1us ticks, so 20us jitter is 1.8 tick which equals 2
319 // after rounding to int.
320 assert_eq!(report.jitter, 2);
321 assert_eq!(report.jitter, r.jitter_in_rtp_ts());
322 }
323 
324 #[test]
325 fn expected_received_loss() {
326 let first = 14.into();
327 let last = 17.into();
328 let expected = expected(first, last);
329 assert_eq!(expected, 4);
330 // none of 4 was lost
331 assert_eq!(packets_lost(expected, 4), 0);
332 // one of 4 was lost:329
333 assert_eq!(packets_lost(expected, 3), 1);
334 }
335 
336 #[test]
337 fn expected_overflow() {
338 let last = 0x7fff_ffff_ffff_ffff_u64.into();
339 let first = 0_u64.into();
340 let expected = expected(first, last);
341 assert_eq!(expected, i64::MAX);
342 }
343 
344 #[test]
345 fn receiver_report() {
346 let mut r = ReceiverRegister::new(None);
347 let now = Instant::now();
348 let rtp_time = 0;
349 
350 // 50 % lost
351 for i in 10..14 {
352 r.update((i as u64).into(), now, rtp_time, 90_000);
353 }
354 r.update(19.into(), now, rtp_time, 90_000);
355 
356 let report = r.reception_report().expect("some report");
357 assert_eq!(128, report.fraction_lost);
358 assert_eq!(5, report.packets_lost);
359 assert_eq!(19, report.max_seq);
360 assert_eq!(0, report.jitter);
361 }
362 
363 #[test]
364 fn simple_jitter_computation() {
365 // SimpleJitterComputation from receive_statistics_unittest.cc
366 const MS_PER_PACKET: u64 = 20;
367 const CODEC_SAMPLE_RATE: u32 = 48_000;
368 const SAMPLES_PER_PACKET: u32 = MS_PER_PACKET as u32 * CODEC_SAMPLE_RATE / 1_000;
369 const LATE_ARRIVAL_DELTA_MS: u64 = 100;
370 const LATE_DELTA_SAMPLES: u32 = LATE_ARRIVAL_DELTA_MS as u32 * CODEC_SAMPLE_RATE / 1_000;
371 
372 let mut clock = Instant::now();
373 let mut r = ReceiverRegister::new(None);
374 
375 r.update_time(clock, 0, CODEC_SAMPLE_RATE);
376 clock += Duration::from_millis(MS_PER_PACKET + LATE_ARRIVAL_DELTA_MS);
377 r.update_time(clock, SAMPLES_PER_PACKET, CODEC_SAMPLE_RATE);
378 
379 assert_eq!(r.jitter_in_rtp_ts(), LATE_DELTA_SAMPLES / 16);
380 }
381 
382 #[test]
383 fn all_packets_have_same_frequency() {
384 // AllPacketsHaveSamePayloadTypeFrequency from receive_statistics_unittest.cc
385 let mut clock = Instant::now();
386 let mut r = ReceiverRegister::new(None);
387 
388 r.update_time(clock, 1, 8_000);
389 clock += Duration::from_millis(50);
390 r.update_time(clock, 1 + 160, 8_000);
391 clock += Duration::from_millis(50);
392 r.update_time(clock, 1 + 160 + 160, 8_000);
393 
394 // packet1: no jitter calculation
395 // packet2: jitter = 0[jitter] + (abs(50[receive time ms] *
396 // 8[frequency KHz] - 160[timestamp diff]) * 16 - 0[jitter] + 8)
397 // / 16 = 240
398 // packet3: jitter = 240[jitter] + (abs(50[receive time ms] *
399 // 8[frequency KHz] - 160[timestamp diff]) * 16 - 240[jitter] + 8)
400 // / 16 = 465
401 // final jitter: 465 / 16 = 29
402 assert_eq!(r.jitter_in_rtp_ts(), 29);
403 }
404 
405 #[test]
406 fn jitter_rtp_timestamp_rollover() {
407 // Same as jitter_same_frequency_three_packets but the timestamps are
408 // anchored so the u32 boundary falls between packets 1 and 2.
409 
410 let rtp_time_1 = u32::MAX - 79;
411 let rtp_time_2 = rtp_time_1.wrapping_add(160);
412 let rtp_time_3 = rtp_time_2.wrapping_add(160);
413 
414 let mut clock = Instant::now();
415 let mut r = ReceiverRegister::new(None);
416 
417 r.update_time(clock, rtp_time_1, 8_000);
418 clock += Duration::from_millis(50);
419 r.update_time(clock, rtp_time_2, 8_000);
420 clock += Duration::from_millis(50);
421 r.update_time(clock, rtp_time_3, 8_000);
422 
423 // Same result as jitter_same_frequency_three_packets.
424 assert_eq!(r.jitter_in_rtp_ts(), 29);
425 }
426}