#[cfg(test)]
use std::time::Duration;
use std::time::Instant;
use crate::RtpTimestamp;
#[derive(Debug, Clone)]
pub struct JitterEstimator {
jitter: f64,
last_arrival: Option<Instant>,
last_timestamp: Option<RtpTimestamp>,
clock_rate: u32,
max_jitter: f64,
min_jitter: f64,
samples: u64,
avg_jitter: f64,
}
impl JitterEstimator {
pub fn new(clock_rate: u32) -> Self {
Self {
jitter: 0.0,
last_arrival: None,
last_timestamp: None,
clock_rate,
max_jitter: 0.0,
min_jitter: f64::MAX,
samples: 0,
avg_jitter: 0.0,
}
}
pub fn update(&mut self, timestamp: RtpTimestamp, arrival: Instant) -> f64 {
if let (Some(last_arrival), Some(last_timestamp)) = (self.last_arrival, self.last_timestamp)
{
let arrival_delta = arrival.duration_since(last_arrival).as_secs_f64();
let ts_delta = timestamp_delta(last_timestamp, timestamp, self.clock_rate);
let transit_delta = arrival_delta - ts_delta;
self.jitter += (transit_delta.abs() - self.jitter) / 16.0;
self.max_jitter = self.max_jitter.max(self.jitter);
self.min_jitter = self.min_jitter.min(self.jitter);
self.samples += 1;
self.avg_jitter += (self.jitter - self.avg_jitter) / (self.samples as f64);
}
self.last_arrival = Some(arrival);
self.last_timestamp = Some(timestamp);
self.jitter
}
pub fn get_jitter(&self) -> f64 {
self.jitter
}
pub fn get_jitter_ms(&self) -> f64 {
self.jitter * 1000.0
}
pub fn get_max_jitter_ms(&self) -> f64 {
self.max_jitter * 1000.0
}
pub fn get_min_jitter_ms(&self) -> f64 {
self.min_jitter * 1000.0
}
pub fn get_avg_jitter_ms(&self) -> f64 {
self.avg_jitter * 1000.0
}
pub fn reset(&mut self) {
self.jitter = 0.0;
self.last_arrival = None;
self.last_timestamp = None;
self.max_jitter = 0.0;
self.min_jitter = f64::MAX;
self.samples = 0;
self.avg_jitter = 0.0;
}
}
fn timestamp_delta(ts1: RtpTimestamp, ts2: RtpTimestamp, clock_rate: u32) -> f64 {
if clock_rate == 0 {
return 0.0;
}
let delta = if ts2 >= ts1 {
ts2 - ts1
} else {
(u32::MAX - ts1) + ts2 + 1
};
(delta as f64) / (clock_rate as f64)
}
#[cfg(test)]
mod tests {
use super::*;
use std::thread::sleep;
#[test]
fn test_timestamp_delta() {
let delta = timestamp_delta(1000, 2000, 8000);
assert!((delta - 0.125).abs() < 0.000001);
let delta_wraparound = timestamp_delta(4294967295, 1000, 8000);
assert!((delta_wraparound - 0.125125).abs() < 0.000001);
assert_eq!(timestamp_delta(1000, 2000, 0), 0.0);
}
#[test]
fn test_jitter_estimation() {
let mut estimator = JitterEstimator::new(8000);
let now = Instant::now();
estimator.update(0, now);
assert_eq!(estimator.get_jitter(), 0.0);
sleep(Duration::from_millis(20));
let packet2_time = Instant::now();
estimator.update(160, packet2_time); assert!(estimator.get_jitter() < 0.001);
sleep(Duration::from_millis(1)); let packet3_time = Instant::now();
estimator.update(320, packet3_time);
sleep(Duration::from_millis(60)); let packet4_time = Instant::now();
estimator.update(480, packet4_time);
sleep(Duration::from_millis(1));
let packet5_time = Instant::now();
estimator.update(640, packet5_time);
assert!(
estimator.get_jitter() > 0.001,
"Jitter value is {} which is too small",
estimator.get_jitter()
);
assert!(estimator.get_max_jitter_ms() >= estimator.get_jitter_ms());
assert!(estimator.get_min_jitter_ms() <= estimator.get_jitter_ms());
}
}