diff --git a/net/rtp/src/opus/mod.rs b/net/rtp/src/opus/mod.rs index 7ec136ac..493e2b1e 100644 --- a/net/rtp/src/opus/mod.rs +++ b/net/rtp/src/opus/mod.rs @@ -2,3 +2,7 @@ pub mod depay; pub mod pay; + +#[allow(clippy::module_inception)] +#[cfg(test)] +mod tests; diff --git a/net/rtp/src/opus/tests/mod.rs b/net/rtp/src/opus/tests/mod.rs new file mode 100644 index 00000000..a79d7e29 --- /dev/null +++ b/net/rtp/src/opus/tests/mod.rs @@ -0,0 +1,3 @@ +// SPDX-License-Identifier: MPL-2.0 + +mod tests; diff --git a/net/rtp/src/opus/tests/tests.rs b/net/rtp/src/opus/tests/tests.rs new file mode 100644 index 00000000..fb034c25 --- /dev/null +++ b/net/rtp/src/opus/tests/tests.rs @@ -0,0 +1,141 @@ +// GStreamer RTP Opus Payloader / Depayloader - unit tests +// +// Copyright (C) 2024 Tim-Philipp Müller +// +// This Source Code Form is subject to the terms of the Mozilla Public License, v2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at +// . +// +// SPDX-License-Identifier: MPL-2.0 + +use crate::tests::{run_test_pipeline, ExpectedBuffer, ExpectedPacket, Source}; + +fn init() { + use std::sync::Once; + static INIT: Once = Once::new(); + + INIT.call_once(|| { + gst::init().unwrap(); + crate::plugin_register_static().expect("rtpopus test"); + }); +} + +// test_opus_pay_dtx +// +// Make sure payloader drops any DTX packets by the encoder (if so requested via the property) +// +#[test] +fn test_opus_pay_dtx() { + // gst-launch-1.0 audiotestsrc wave=silence + // ! opusenc dtx=true bitrate-type=vbr + // ! fakesink silent=false dump=true + const OPUS_BUFFER_SILENCE: &[u8] = &[0xf8, 0xff, 0xfe]; + const OPUS_BUFFER_SILENCE_DTX: &[u8] = &[0xf8]; + + fn make_buffer( + data: &'static [u8], + pts: gst::ClockTime, + duration: gst::ClockTime, + flags: gst::BufferFlags, + ) -> gst::Buffer { + let mut buf = gst::Buffer::from_slice(data); + + let buf_ref = buf.get_mut().unwrap(); + buf_ref.set_pts(pts); + buf_ref.set_duration(duration); + buf_ref.set_flags(flags); + + buf + } + + init(); + + for dtx_prop in [false, true] { + eprintln!("Testing rtpopuspay2 dtx={dtx_prop} .."); + + let input_caps = gst::Caps::builder("audio/x-opus") + .field("rate", 48000i32) + .field("channels", 1i32) + .field("channel-mapping-family", 0i32) + .build(); + + let input_buffers = vec![ + make_buffer( + OPUS_BUFFER_SILENCE, + gst::ClockTime::ZERO, + gst::ClockTime::from_useconds(13500), + gst::BufferFlags::DISCONT, + ), + make_buffer( + OPUS_BUFFER_SILENCE, + gst::ClockTime::from_useconds(13500), + gst::ClockTime::from_mseconds(20), + gst::BufferFlags::empty(), + ), + make_buffer( + OPUS_BUFFER_SILENCE_DTX, + gst::ClockTime::from_useconds(33500), + gst::ClockTime::from_mseconds(20), + gst::BufferFlags::empty(), + ), + ]; + + // TODO: check durations? + let mut expected_pay = vec![ + vec![ExpectedPacket::builder() + .pts(gst::ClockTime::ZERO) + .flags(gst::BufferFlags::DISCONT | gst::BufferFlags::MARKER) + .pt(96) + .rtp_time(0) + .marker_bit(true) + .build()], + vec![ExpectedPacket::builder() + .pts(gst::ClockTime::from_useconds(13500)) + .flags(gst::BufferFlags::empty()) + .pt(96) + .rtp_time(648) + .marker_bit(false) + .build()], + vec![ExpectedPacket::builder() + .pts(gst::ClockTime::from_useconds(33500)) + .flags(gst::BufferFlags::empty()) + .pt(96) + .rtp_time(648 + 960) + .marker_bit(false) + .build()], + ]; + + // TODO: check durations? + let mut expected_depay = vec![ + vec![ExpectedBuffer::builder() + .pts(gst::ClockTime::ZERO) + .size(3) + .flags(gst::BufferFlags::DISCONT | gst::BufferFlags::RESYNC) + .build()], + vec![ExpectedBuffer::builder() + .pts(gst::ClockTime::from_useconds(13500)) + .size(3) + .flags(gst::BufferFlags::empty()) + .build()], + vec![ExpectedBuffer::builder() + .pts(gst::ClockTime::from_useconds(33500)) + .size(1) + .flags(gst::BufferFlags::empty()) + .build()], + ]; + + if dtx_prop { + // Payloader should drop DTX buffer if dtx=true and not output it + expected_pay.pop(); + expected_depay.pop(); + } + + run_test_pipeline( + Source::Buffers(input_caps, input_buffers), + &format!("rtpopuspay2 dtx={dtx_prop}"), + "rtpopusdepay2", + expected_pay, + expected_depay, + ); + } +}