use log::{info, trace};
use rand::{prelude::StdRng, SeedableRng};
use rand_distr::{Bernoulli, Normal};
use srt_protocol::connection::Input;
use std::{
cmp::min,
str,
time::{Duration, Instant},
};
pub mod simulator;
use simulator::*;
use srt_protocol::options::PacketCount;
#[test]
fn not_enough_latency() {
do_not_enough_latency(14133229019647651772, 200);
do_not_enough_latency(7252484344775749023, 1000);
do_not_enough_latency(6785379667375872404, 1000);
do_not_enough_latency(12543789221422496569, 1000);
for _ in 0..100 {
do_not_enough_latency(rand::random(), 1000);
}
}
fn do_not_enough_latency(seed: u64, packets: usize) {
println!("not_enough_latency seed is {seed}");
let _ = pretty_env_logger::try_init();
const PACKET_SPACING: Duration = Duration::from_millis(10);
let start = Instant::now();
let rng = StdRng::seed_from_u64(seed);
let mut simulation = RandomLossSimulation {
rng,
delay_dist: Normal::new(1.5, 0.2).unwrap(),
drop_dist: Bernoulli::new(0.01).unwrap(),
};
let (mut network, mut sender, mut receiver) =
simulation.build(start, Duration::from_secs(2), PacketCount(8192));
input_data_simulation(start, packets, PACKET_SPACING, &mut network.sender);
let mut now = start;
let mut total_recvd = 0;
let mut total_dropped = 0;
let mut last_data = 0;
loop {
let sender_next_time = if sender.is_open() {
assert_eq!(sender.next_data(now), None);
while let Some(packet) = sender.next_packet(now) {
match simulation.next_packet_schedule(now) {
Some(release_at) => network.send(release_at, packet),
None => trace!("Dropping {:?}", packet),
}
}
let next_timer = sender.check_timers(now);
let (next_time, input) = network.sender.select_next_input(now, next_timer);
match input {
Input::Data(data) => sender.handle_data_input(next_time, data),
Input::Packet(packet) => sender.handle_packet_input(next_time, packet),
_ => {}
};
Some(next_time)
} else {
None
};
let receiver_next_time = if receiver.is_open() {
while let Some((_, by)) = receiver.next_data(now) {
total_recvd += 1;
let id = str::from_utf8(&by).unwrap().parse().unwrap();
assert!(id > last_data, "Received {id} after {last_data}");
if last_data + 1 != id {
info!("Packets [{}, {}) dropped", last_data + 1, id);
total_dropped += id - (last_data + 1);
}
last_data = id;
}
while let Some(packet) = receiver.next_packet(now) {
match simulation.next_packet_schedule(now) {
Some(release_at) => network.send(release_at, packet),
None => trace!("Dropping {:?}", packet),
}
}
let next_timer = receiver.check_timers(now);
let (next_time, input) = network.receiver.select_next_input(now, next_timer);
match input {
Input::Data(data) => receiver.handle_data_input(now, data),
Input::Packet(packet) => receiver.handle_packet_input(now, packet),
_ => {}
};
Some(next_time)
} else {
None
};
let next_time = match (sender_next_time, receiver_next_time) {
(Some(s), Some(r)) => min(s, r),
(Some(s), None) => s,
(None, Some(r)) => r,
_ => break,
};
let delta = next_time - now;
trace!("Delta = {:?}", delta);
now = next_time;
}
assert_eq!(total_dropped + total_recvd + (packets - last_data), packets);
assert!(
total_recvd > packets * 2 / 3,
"received {} packtes, expected {}",
total_recvd,
packets * 2 / 3
);
assert!(
total_recvd <= packets,
"received all ({total_recvd}) packets, expected < {packets}"
);
}