diff --git a/src/packet/mod.rs b/src/packet/mod.rs index 768fbca6..a650f6ce 100644 --- a/src/packet/mod.rs +++ b/src/packet/mod.rs @@ -209,7 +209,7 @@ pub(crate) enum CodecDepacketizer { impl From for CodecPacketizer { fn from(c: Codec) -> Self { match c { - Codec::Opus => CodecPacketizer::Opus(OpusPacketizer), + Codec::Opus => CodecPacketizer::Opus(OpusPacketizer::default()), Codec::H264 => CodecPacketizer::H264(H264Packetizer::default()), Codec::H265 => unimplemented!("Missing packetizer for H265"), Codec::Vp8 => CodecPacketizer::Vp8(Vp8Packetizer::default()), diff --git a/src/packet/opus.rs b/src/packet/opus.rs index 365da501..d6628e6a 100644 --- a/src/packet/opus.rs +++ b/src/packet/opus.rs @@ -2,7 +2,10 @@ use super::{CodecExtra, Depacketizer, MediaKind, PacketError, Packetizer}; /// Packetizes Opus RTP packets. #[derive(Default, Debug, Copy, Clone)] -pub struct OpusPacketizer; +pub struct OpusPacketizer { + // stores if a marker was previously set + marker: bool, +} impl Packetizer for OpusPacketizer { fn packetize(&mut self, mtu: usize, payload: &[u8]) -> Result>, PacketError> { @@ -23,8 +26,23 @@ impl Packetizer for OpusPacketizer { } fn is_marker(&mut self, data: &[u8], previous: Option<&[u8]>, last: bool) -> bool { - // TODO: dtx - false + // any non silenced packet would generally have more than 2 byts + let mut is_marker = data.len() > 2; + + match self.marker { + true => { + if !is_marker { + self.marker = false; + } + is_marker = false; + } + false => { + if is_marker { + self.marker = true; + } + } + } + is_marker } } @@ -84,7 +102,7 @@ mod test { #[test] fn test_opus_payload() -> Result<(), PacketError> { - let mut pck = OpusPacketizer; + let mut pck = OpusPacketizer::default(); let empty = &[]; let payload = &[0x90, 0x90, 0x90]; diff --git a/tests/rtp_to_frame.rs b/tests/talk_start_spurt.rs similarity index 53% rename from tests/rtp_to_frame.rs rename to tests/talk_start_spurt.rs index 62f3af14..0c52b1e8 100644 --- a/tests/rtp_to_frame.rs +++ b/tests/talk_start_spurt.rs @@ -2,7 +2,7 @@ use std::collections::VecDeque; use std::time::Duration; use str0m::format::Codec; -use str0m::media::MediaKind; +use str0m::media::{Frequency, MediaKind, MediaTime}; use str0m::rtp::{ExtensionValues, Ssrc}; use str0m::{Event, Rtc, RtcError}; @@ -10,7 +10,7 @@ mod common; use common::{connect_l_r_with_rtc, init_log, progress}; #[test] -pub fn audio_start_of_talk_spurt() -> Result<(), RtcError> { +pub fn audio_start_of_talk_spurt_frame() -> Result<(), RtcError> { init_log(); let rtc1 = Rtc::builder().set_rtp_mode(true).build(); @@ -108,3 +108,103 @@ pub fn audio_start_of_talk_spurt() -> Result<(), RtcError> { Ok(()) } + +#[test] +pub fn audio_start_of_talk_spurt_rtp() -> Result<(), RtcError> { + init_log(); + + let rtc1 = Rtc::builder().build(); + let rtc2 = Rtc::builder() + .set_reordering_size_audio(0) + .set_rtp_mode(true) + .build(); + + let (mut l, mut r) = connect_l_r_with_rtc(rtc1, rtc2); + + let mid = "audio".into(); + let ssrc_tx: Ssrc = 1337.into(); + + l.direct_api().declare_media(mid, MediaKind::Audio); + l.direct_api().declare_stream_tx(ssrc_tx, None, mid, None); + r.direct_api().declare_media(mid, MediaKind::Audio); + + let max = l.last.max(r.last); + l.last = max; + r.last = max; + + let params = l.params_opus(); + + assert_eq!(params.spec().codec, Codec::Opus); + let pt = params.pt(); + + let to_write: Vec<&[u8]> = vec![ + // 1 + &[0x1], + // 2 + &[0x1, 0x2, 0x3, 0x4], + // 4 + &[0x9, 0xa, 0xb, 0xc], + // 3 + &[0x5, 0x6, 0x7, 0x8], + // 5 + &[0x1], + // 6 + &[0x9, 0xa, 0xb, 0xc], + ]; + + let mut to_write: VecDeque<_> = to_write.into(); + + let mut write_at = l.last + Duration::from_millis(300); + + let mut counts: Vec = vec![0, 1, 2, 4, 3, 5, 6]; + + loop { + if l.start + l.duration() > write_at { + write_at = l.last + Duration::from_millis(300); + if let Some(packet) = to_write.pop_front() { + let wallclock = l.start + l.duration(); + + let count = counts.remove(0); + let time = count * 1000 + 47_000_000; + + l.writer(mid) + .unwrap() + .write( + pt, + wallclock, + MediaTime::new(time, Frequency::FORTY_EIGHT_KHZ), + packet.to_vec(), + ) + .unwrap(); + } + } + + progress(&mut l, &mut r)?; + + if l.duration() > Duration::from_secs(10) { + break; + } + } + + let rtp_packets: Vec<_> = r + .events + .iter() + .filter_map(|(_, e)| { + if let Event::RtpPacket(p) = e { + Some(p) + } else { + None + } + }) + .collect(); + + assert_eq!(rtp_packets.len(), 6); + let is_marker = [false, true, false, false, false, true]; + + rtp_packets + .iter() + .enumerate() + .for_each(|(i, r)| assert_eq!(r.header.marker, is_marker[i])); + + Ok(()) +}