use std::net::Ipv4Addr;
use std::time::{Duration, Instant};
use str0m::Rtc;
use str0m::format::Codec;
use str0m::media::{Direction, MediaData, MediaKind};
use str0m::{Candidate, Event, RtcError};
use tracing::info_span;
mod common;
use common::{Peer, TestRtc, init_crypto_default, init_log, progress};
#[test]
pub fn contiguous_all_the_way() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let output = Server::with_vp8_input()
.timeout(Duration::from_secs(10))
.get_output()?;
let mut count = 0;
for data in output {
assert!(data.contiguous);
count += 1;
}
assert_eq!(count, 101);
Ok(())
}
#[test]
pub fn not_contiguous() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let output = Server::with_vp8_input()
.skip_packet(14337)
.timeout(Duration::from_secs(5))
.get_output()?;
let mut count = 0;
for data in output {
count += 1;
let assume_contiguous = !data.seq_range.contains(&14339.into());
assert_eq!(assume_contiguous, data.contiguous);
}
assert_eq!(count, 99);
Ok(())
}
#[test]
pub fn vp9_contiguous_all_the_way() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let output = Server::with_vp9_input().get_output()?;
let mut count = 0;
for data in output {
assert!(data.contiguous);
count += 1;
}
assert_eq!(count, 15);
Ok(())
}
#[test]
pub fn vp9_not_contiguous() -> Result<(), RtcError> {
init_log();
init_crypto_default();
let output = Server::with_vp9_input().skip_packet(30952).get_output()?;
let mut count = 0;
for data in output {
count += 1;
let assume_contiguous = !data.seq_range.contains(&30953.into());
assert_eq!(assume_contiguous, data.contiguous);
}
assert_eq!(count, 14);
Ok(())
}
struct Server {
codec: Codec,
input_data: common::PcapData,
skip_packet: Option<u16>,
timeout: Option<Duration>,
}
impl Server {
fn with_vp8_input() -> Self {
Self::new(Codec::Vp8, common::vp8_data())
}
fn with_vp9_input() -> Self {
Self::new(Codec::Vp9, common::vp9_contiguous_data())
}
fn new(codec: Codec, input_data: common::PcapData) -> Self {
Self {
codec,
input_data,
skip_packet: None,
timeout: None,
}
}
fn skip_packet(mut self, packet: u16) -> Self {
self.skip_packet = Some(packet);
self
}
fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = Some(timeout);
self
}
fn get_output(self) -> Result<Vec<MediaData>, RtcError> {
let mut l = TestRtc::new(Peer::Left);
let rtc_r = Rtc::builder()
.set_reordering_size_video(5)
.build(Instant::now());
let mut r = TestRtc::new_with_rtc(info_span!("R"), rtc_r);
l.add_local_candidate(Candidate::host(
(Ipv4Addr::new(1, 1, 1, 1), 1000).into(),
"udp",
)?);
r.add_local_candidate(Candidate::host(
(Ipv4Addr::new(2, 2, 2, 2), 2000).into(),
"udp",
)?);
let mut change = l.sdp_api();
let mid = change.add_media(MediaKind::Video, Direction::SendOnly, None, None, None);
let (offer, pending) = change.apply().unwrap();
let answer = r.rtc.sdp_api().accept_offer(offer)?;
l.rtc.sdp_api().accept_answer(pending, answer)?;
loop {
if l.is_connected() || r.is_connected() {
break;
}
progress(&mut l, &mut r)?;
}
let max = l.last.max(r.last);
l.last = max;
r.last = max;
let params = match self.codec {
Codec::Vp8 => l.params_vp8(),
Codec::Vp9 => l.params_vp9(),
_ => unimplemented!(),
};
assert_eq!(params.spec().codec, self.codec);
let pt = params.pt();
for (relative, header, payload) in self.input_data {
if Some(header.sequence_number) == self.skip_packet {
continue;
}
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_by_mid(mid, None).unwrap();
tx.write_rtp(
pt,
header.sequence_number(None),
header.timestamp,
absolute,
header.marker,
header.ext_vals,
true,
payload,
)
.unwrap();
progress(&mut l, &mut r)?;
if let Some(duration) = self.timeout {
if l.duration() > duration {
break;
}
}
}
progress(&mut l, &mut r)?;
let events = r
.events
.into_iter()
.filter_map(|(_, e)| {
if let Event::MediaData(d) = e {
Some(d)
} else {
None
}
})
.collect();
Ok(events)
}
}