Skip to content

Commit

Permalink
feat: add marker bit when packetizing opus.
Browse files Browse the repository at this point in the history
incase of silence opus, rtp payload sets the marker bit after a talking spurt.
usually the data in silence packets are empty, it just uses 1-2 bytes for header.

introduced a marker state inside the OpusPacketizer since we don't have
access to previous packet incase of audio.

fixes algesten#125
  • Loading branch information
ramyak-mehra committed Oct 13, 2024
1 parent 5c4c9d5 commit 1066c4a
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/packet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ pub(crate) enum CodecDepacketizer {
impl From<Codec> 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()),
Expand Down
26 changes: 22 additions & 4 deletions src/packet/opus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<Vec<u8>>, PacketError> {
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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];

Expand Down
104 changes: 102 additions & 2 deletions tests/rtp_to_frame.rs → tests/talk_start_spurt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ 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};

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();
Expand Down Expand Up @@ -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<u64> = 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(())
}

0 comments on commit 1066c4a

Please sign in to comment.