#[cfg(test)]
mod tests {
use crate::twcc::twcc::Responder;
use rtcp::header;
use rtcp::header::Header;
use rtcp::header::PacketType;
use rtcp::transport_feedbacks::transport_layer_cc::SymbolSizeTypeTcc;
use rtcp::transport_feedbacks::transport_layer_cc::SymbolTypeTcc;
use webrtc_util::Marshal;
#[test]
fn test_run_length_chunk() {
#[derive(Default, Clone)]
pub struct Fields {
len: u16,
}
#[derive(Default, Clone)]
pub struct Test {
pub name: String,
fields: Fields,
args: Args,
pub want_err: bool,
want_bytes: Vec<u8>,
}
#[derive(Default, Clone)]
pub struct Args {
symbol: SymbolTypeTcc,
run_length: u16,
}
let tests = [
Test {
name: String::from("Must not return error"),
args: Args {
symbol: SymbolTypeTcc::PacketNotReceived,
run_length: 221,
},
want_err: false,
want_bytes: vec![0, 0xdd],
..Default::default()
},
Test {
name: String::from("Must set run length after padding"),
fields: Fields { len: 1 },
args: Args {
symbol: SymbolTypeTcc::PacketReceivedWithoutDelta,
run_length: 24,
},
want_bytes: vec![0, 0x60, 0x18],
..Default::default()
},
];
for test in tests {
let mut t = Responder::new(0);
t.len = test.fields.len;
for _i in 0..test.fields.len {
t.payload.push(0);
}
let rv = t.write_run_length_chunk(test.args.symbol as u16, test.args.run_length);
assert!(rv.is_ok());
assert_eq!(test.want_bytes, t.payload);
}
}
#[test]
fn test_write_status_symbol_chunk() {
#[derive(Default, Clone)]
pub struct Fields {
len: u16,
}
#[derive(Default, Clone)]
pub struct Test {
pub name: String,
fields: Fields,
args: Args,
want_bytes: Vec<u8>,
}
#[derive(Default, Clone)]
pub struct Args {
symbol_size: SymbolSizeTypeTcc,
symbols: Vec<SymbolTypeTcc>,
}
let tests = [
Test {
name: String::from("Must not return error"),
args: Args {
symbol_size: SymbolSizeTypeTcc::OneBit,
symbols: vec![
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
],
},
want_bytes: vec![0x9F, 0x1C],
..Default::default()
},
Test {
name: String::from("Must set symbol chunk after padding"),
fields: Fields { len: 1 },
args: Args {
symbol_size: SymbolSizeTypeTcc::TwoBit,
symbols: vec![
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedWithoutDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
],
},
want_bytes: vec![0x0, 0xcd, 0x50],
},
];
for test in tests {
let mut t = Responder::new(0);
t.len = test.fields.len;
for _i in 0..test.fields.len {
t.payload.push(0);
}
for (idx, symbol) in test.args.symbols.into_iter().enumerate() {
t.create_status_symbol_chunk(test.args.symbol_size, symbol as u16, idx as u16);
}
let rv = t.write_status_symbol_chunk(test.args.symbol_size);
assert!(rv.is_ok());
assert_eq!(test.want_bytes, t.payload);
}
}
#[test]
fn test_write_delta() {
let a = 0x8000;
#[derive(Default, Clone)]
pub struct Fields {
delta_len: usize,
}
#[derive(Default, Clone)]
pub struct Args {
delta_type: SymbolTypeTcc,
delta: u16,
}
#[derive(Default, Clone)]
pub struct Test {
pub name: String,
fields: Fields,
args: Args,
want_bytes: Vec<u8>,
}
let tests = [
Test {
name: String::from("Must set correct small delta"),
args: Args {
delta_type: SymbolTypeTcc::PacketReceivedSmallDelta,
delta: 255,
},
want_bytes: vec![0xFF],
..Default::default()
},
Test {
name: String::from("Must set correct small delta with padding"),
fields: Fields { delta_len: 1 },
args: Args {
delta_type: SymbolTypeTcc::PacketReceivedSmallDelta,
delta: 255,
},
want_bytes: vec![0, 0xFF],
},
Test {
name: String::from("Must set correct large delta"),
args: Args {
delta_type: SymbolTypeTcc::PacketReceivedLargeDelta,
delta: 32767,
},
want_bytes: vec![0x7F, 0xFF],
..Default::default()
},
Test {
name: String::from("Must set correct large delta with padding"),
fields: Fields { delta_len: 1 },
args: Args {
delta_type: SymbolTypeTcc::PacketReceivedLargeDelta,
delta: a,
},
want_bytes: vec![0, 0x80, 0x00],
},
];
for test in tests {
let mut t = Responder::new(0);
t.delta_len = test.fields.delta_len;
for _i in 0..test.fields.delta_len {
t.deltas.push(0);
}
let rv = t.write_delta(test.args.delta_type, test.args.delta);
assert!(rv.is_ok());
assert_eq!(test.want_bytes, t.deltas[..t.delta_len]);
}
}
#[test]
fn test_write_header() {
#[derive(Default, Clone)]
pub struct Fields {
tcc_pkt_ctn: u8,
s_ssrc: u32,
m_ssrc: u32,
}
#[derive(Default, Clone)]
pub struct Args {
b_sn: u16,
packet_count: u16,
ref_time: u32,
}
#[derive(Default, Clone)]
pub struct Test {
pub name: String,
fields: Fields,
args: Args,
want_bytes: Vec<u8>,
}
let tests = [Test {
name: String::from("Must construct correct header"),
fields: Fields {
tcc_pkt_ctn: 23,
s_ssrc: 4195875351,
m_ssrc: 1124282272,
},
args: Args {
b_sn: 153,
packet_count: 1,
ref_time: 4057090,
},
want_bytes: vec![
0xfa, 0x17, 0xfa, 0x17, 0x43, 0x3, 0x2f, 0xa0, 0x0, 0x99, 0x0, 0x1, 0x3d, 0xe8,
0x2, 0x17,
],
}];
for test in tests {
let mut t = Responder::new(0);
t.pkt_ctn = test.fields.tcc_pkt_ctn;
t.m_ssrc = test.fields.m_ssrc;
t.s_ssrc = test.fields.s_ssrc;
let rv = t.write_header(test.args.b_sn, test.args.packet_count, test.args.ref_time);
assert!(rv.is_ok());
assert_eq!(test.want_bytes, t.payload[..16]);
}
}
#[test]
fn test_tcc_packet() {
let want_bytes = vec![
0xfa, 0x17, 0xfa, 0x17, 0x43, 0x3, 0x2f, 0xa0, 0x0, 0x99, 0x0, 0x1, 0x3d, 0xe8, 0x2,
0x17, 0x60, 0x18, 0x0, 0xdd, 0x9F, 0x1C, 0xcd, 0x50,
];
let delta = vec![0xff, 0x80, 0xaa];
let symbol1 = vec![
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
];
let symbol2 = vec![
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketReceivedWithoutDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketReceivedSmallDelta,
SymbolTypeTcc::PacketNotReceived,
SymbolTypeTcc::PacketNotReceived,
];
let mut t = Responder::new(0);
t.pkt_ctn = 23;
t.m_ssrc = 1124282272;
t.s_ssrc = 4195875351;
let mut rv = t.write_header(153, 1, 4057090);
assert!(rv.is_ok());
rv = t.write_run_length_chunk(SymbolTypeTcc::PacketReceivedWithoutDelta as u16, 24);
assert!(rv.is_ok());
rv = t.write_run_length_chunk(SymbolTypeTcc::PacketNotReceived as u16, 221);
assert!(rv.is_ok());
for (i, v) in symbol1.iter().enumerate() {
t.create_status_symbol_chunk(SymbolSizeTypeTcc::OneBit, *v as u16, i as u16);
}
rv = t.write_status_symbol_chunk(SymbolSizeTypeTcc::OneBit);
assert!(rv.is_ok());
for (i, v) in symbol2.iter().enumerate() {
t.create_status_symbol_chunk(SymbolSizeTypeTcc::TwoBit, *v as u16, i as u16);
}
rv = t.write_status_symbol_chunk(SymbolSizeTypeTcc::TwoBit);
assert!(rv.is_ok());
t.delta_len = delta.len();
assert_eq!(want_bytes, t.payload[..24]);
let mut p_len = t.len + t.delta_len as u16 + 4;
let pad = (p_len % 4) != 0;
while p_len % 4 != 0 {
p_len += 1;
}
let hdr = Header {
padding: pad,
length: p_len / 4 - 1,
count: header::FORMAT_TCC,
packet_type: PacketType::TransportSpecificFeedback,
};
assert_eq!(p_len as usize, want_bytes.len() + 3 + 4 + 1);
let mut raw_packet_data: Vec<u8> = Vec::new();
let rv = hdr.marshal_to(&mut raw_packet_data[..]); assert!(rv.is_ok());
}
}