mod common;
use std::time::Duration;
use common::{connect_l_r, init_crypto_default, progress, vp8_data};
use netem::{GilbertElliot, LossModel, NetemConfig};
use str0m::format::Codec;
use str0m::media::MediaKind;
use str0m::rtp::Ssrc;
use str0m::{Event, RtcError};
use crate::common::init_log;
fn run_loss_test(loss_model: impl Into<LossModel>, seed: u64) -> Result<usize, RtcError> {
init_log();
init_crypto_default();
let (mut l, mut r) = connect_l_r();
let config = NetemConfig::new().loss(loss_model).seed(seed);
r.set_netem(config);
let mid = "vid".into();
let ssrc_tx: Ssrc = 42.into();
let ssrc_rtx: Ssrc = 44.into();
l.direct_api().declare_media(mid, MediaKind::Video);
l.direct_api()
.declare_stream_tx(ssrc_tx, Some(ssrc_rtx), mid, None);
l.direct_api().stream_tx(&ssrc_tx).unwrap().set_rtx_cache(
1024,
Duration::from_secs(3),
Some(0.2),
);
r.direct_api().declare_media(mid, MediaKind::Video);
r.direct_api()
.expect_stream_rx(ssrc_tx, Some(ssrc_rtx), mid, None);
let max = l.last.max(r.last);
l.last = max;
r.last = max;
let params = l.params_vp8();
assert_eq!(params.spec().codec, Codec::Vp8);
let pt = params.pt();
let data = vp8_data();
let packet_count = data.len();
for (relative, header, payload) in data {
while (l.last - max) < relative {
progress(&mut l, &mut r)?;
}
let absolute = max + relative;
let mut direct = l.direct_api();
let tx = direct.stream_tx(&ssrc_tx).unwrap();
tx.write_rtp(
pt,
header.sequence_number(None),
header.timestamp,
absolute,
header.marker,
Default::default(), true,
payload,
)
.unwrap();
progress(&mut l, &mut r)?;
if l.duration() > Duration::from_secs(10) {
break;
}
}
let settle_time = l.duration() + Duration::from_secs(2);
while l.duration() < settle_time {
progress(&mut l, &mut r)?;
}
let mut received_seqs: Vec<u64> = r
.events
.iter()
.filter_map(|(_, e)| {
if let Event::RtpPacket(v) = e {
Some(*v.seq_no)
} else {
None
}
})
.collect();
received_seqs.sort();
println!(
"Sent {} packets, received {} packets",
packet_count,
received_seqs.len()
);
if !received_seqs.is_empty() {
let first = received_seqs[0];
let last = *received_seqs.last().unwrap();
let expected: Vec<u64> = (first..=last).collect();
let missing: Vec<u64> = expected
.iter()
.filter(|s| !received_seqs.contains(s))
.copied()
.collect();
if !missing.is_empty() {
println!("Missing seq numbers from Event::RtpPacket: {:?}", missing);
}
}
Ok(received_seqs.len())
}
#[test]
fn loss_light() -> Result<(), RtcError> {
let loss = GilbertElliot::wifi();
let received = run_loss_test(loss, 12345)?;
assert_eq!(
received, 104,
"Expected 104 packets with light loss, got {}",
received
);
Ok(())
}
#[test]
fn loss_medium() -> Result<(), RtcError> {
let loss = GilbertElliot::wifi_lossy();
let received = run_loss_test(loss, 12345)?;
assert_eq!(
received, 104,
"Expected 104 packets with medium loss, got {}",
received
);
Ok(())
}
#[test]
fn loss_heavy() -> Result<(), RtcError> {
let loss = GilbertElliot::congested();
let received = run_loss_test(loss, 12345)?;
assert_eq!(
received, 104,
"Expected 104 packets with heavy loss, got {}",
received
);
Ok(())
}