From bf7fc30020f9c2c27ae96695d4da493ba4da1615 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Thu, 13 Aug 2026 18:14:43 +0200 Subject: [PATCH 1/2] Fix RRTR originator SSRC and changelog --- CHANGELOG.md | 2 ++ src/streams/receive.rs | 6 +++--- tests/dlrr.rs | 33 +++++++++++++++++++++++---------- 3 files changed, 28 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d6e0268fb..4840fd606 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased + * Respond to RRTR with DLRR #1022 + * Use a local SSRC as the originator of outgoing RRTR reports #PR_NUMBER * Add `DirectApi::send_pli_feedback` to send a PLI with a chosen sender SSRC #1025 # 0.22.0 diff --git a/src/streams/receive.rs b/src/streams/receive.rs index ca6fb3840..3ab3c5f42 100644 --- a/src/streams/receive.rs +++ b/src/streams/receive.rs @@ -585,7 +585,7 @@ impl StreamRx { self.stats.jitter = report.jitter; } - let xr = self.create_extended_receiver_report(now); + let xr = self.create_extended_receiver_report(now, sender_ssrc); trace!( "Created feedback RR/XR ({:?}): {:?} {:?}", @@ -637,14 +637,14 @@ impl StreamRx { } } - fn create_extended_receiver_report(&self, now: Instant) -> ExtendedReport { + fn create_extended_receiver_report(&self, now: Instant, sender_ssrc: Ssrc) -> ExtendedReport { // we only want to report our time to measure RTT, // the source will answer with Dlrr feedback, allowing us to calculate RTT let block = ReportBlock::Rrtr(Rrtr { ntp_time: now.to_system_time(), }); ExtendedReport { - ssrc: self.ssrc, + ssrc: sender_ssrc, blocks: vec![block], } } diff --git a/tests/dlrr.rs b/tests/dlrr.rs index 6475b7e35..0e87c856e 100644 --- a/tests/dlrr.rs +++ b/tests/dlrr.rs @@ -64,19 +64,31 @@ pub fn dlrr_response_to_rrtr() -> Result<(), RtcError> { } } - // R should have sent at least one RRTR. - let rrtr_count = r + let media_ssrc = l .events .iter() - .filter(|(_, e)| { - matches!( - e.as_raw_packet(), - Some(RawPacket::RtcpTx(Rtcp::ExtendedReport(xr))) - if xr.blocks.iter().any(|b| matches!(b, ReportBlock::Rrtr(_))) - ) + .find_map(|(_, e)| match e.as_raw_packet() { + Some(RawPacket::RtpTx(header, _)) => Some(header.ssrc), + _ => None, + }) + .expect("L should have sent RTP"); + + // R should have sent at least one RRTR, using its local RTCP SSRC rather than + // the remote media SSRC it is reporting on. + let rrtr_ssrc = r + .events + .iter() + .find_map(|(_, e)| { + let Some(RawPacket::RtcpTx(Rtcp::ExtendedReport(xr))) = e.as_raw_packet() else { + return None; + }; + xr.blocks + .iter() + .any(|b| matches!(b, ReportBlock::Rrtr(_))) + .then_some(xr.ssrc) }) - .count(); - assert!(rrtr_count > 0, "R should have sent at least one RRTR"); + .expect("R should have sent at least one RRTR"); + assert_ne!(rrtr_ssrc, media_ssrc); // L should have sent at least one DLRR in response. let dlrr_reports: Vec<_> = l @@ -107,6 +119,7 @@ pub fn dlrr_response_to_rrtr() -> Result<(), RtcError> { .unwrap(); assert!(!dlrr.items.is_empty(), "DLRR should have at least one item"); let item = &dlrr.items[0]; + assert_eq!(item.ssrc, rrtr_ssrc); // The last_rr_time field must be the middle 32 bits of the RRTR's NTP timestamp. // Verify it's non-zero and that R received the same value back (round-trip integrity). From ff7348671e19748b4c98b5ab57be8994e11457f7 Mon Sep 17 00:00:00 2001 From: Martin Algesten Date: Thu, 13 Aug 2026 18:15:12 +0200 Subject: [PATCH 2/2] Add PR number to changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4840fd606..68db7e9d4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # Unreleased * Respond to RRTR with DLRR #1022 - * Use a local SSRC as the originator of outgoing RRTR reports #PR_NUMBER + * Use a local SSRC as the originator of outgoing RRTR reports #1027 * Add `DirectApi::send_pli_feedback` to send a PLI with a chosen sender SSRC #1025 # 0.22.0