From 98b4ec4ae015b151355639fcc4067ef77a9f49a8 Mon Sep 17 00:00:00 2001 From: yngrtc Date: Sun, 21 Apr 2024 17:31:33 -0700 Subject: [PATCH] Fix simulcast for firefox (#534) --- rtc-sdp/src/extmap/mod.rs | 3 + rtc/src/constants.rs | 2 - .../peer_connection_internal.rs | 40 ++++++------ rtc/src/peer_connection/sdp/mod.rs | 20 +++--- rtc/src/rtp_transceiver/rtp_receiver/mod.rs | 10 --- .../rtp_receiver/rtp_receiver_test.rs | 62 ++++++++++--------- 6 files changed, 61 insertions(+), 76 deletions(-) diff --git a/rtc-sdp/src/extmap/mod.rs b/rtc-sdp/src/extmap/mod.rs index b7542b4..9e609a5 100644 --- a/rtc-sdp/src/extmap/mod.rs +++ b/rtc-sdp/src/extmap/mod.rs @@ -20,6 +20,9 @@ pub const TRANSPORT_CC_URI: &str = "http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01"; pub const SDES_MID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:mid"; pub const SDES_RTP_STREAM_ID_URI: &str = "urn:ietf:params:rtp-hdrext:sdes:rtp-stream-id"; +pub const SDES_REPAIR_RTP_STREAM_ID_URI: &str = + "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"; + pub const AUDIO_LEVEL_URI: &str = "urn:ietf:params:rtp-hdrext:ssrc-audio-level"; pub const VIDEO_ORIENTATION_URI: &str = "urn:3gpp:video-orientation"; diff --git a/rtc/src/constants.rs b/rtc/src/constants.rs index 5a999d1..c8356c4 100644 --- a/rtc/src/constants.rs +++ b/rtc/src/constants.rs @@ -6,8 +6,6 @@ pub(crate) const RECEIVE_MTU: usize = 1460; pub(crate) const SDP_ATTRIBUTE_RID: &str = "rid"; pub(crate) const SDP_ATTRIBUTE_SIMULCAST: &str = "simulcast"; pub(crate) const GENERATED_CERTIFICATE_ORIGIN: &str = "WebRTC"; -pub(crate) const SDES_REPAIR_RTP_STREAM_ID_URI: &str = - "urn:ietf:params:rtp-hdrext:sdes:repaired-rtp-stream-id"; pub(crate) const DEFAULT_SESSION_SRTP_REPLAY_PROTECTION_WINDOW: usize = 64; pub(crate) const DEFAULT_SESSION_SRTCP_REPLAY_PROTECTION_WINDOW: usize = 64; pub(crate) const DEFAULT_DTLS_REPLAY_PROTECTION_WINDOW: usize = 64; diff --git a/rtc/src/peer_connection/peer_connection_internal.rs b/rtc/src/peer_connection/peer_connection_internal.rs index d1f0d60..4129abd 100644 --- a/rtc/src/peer_connection/peer_connection_internal.rs +++ b/rtc/src/peer_connection/peer_connection_internal.rs @@ -15,7 +15,7 @@ use crate::stats::{ StatsReportType, }; use crate::track::TrackStream; -use crate::{SDES_REPAIR_RTP_STREAM_ID_URI, SDP_ATTRIBUTE_RID}; +use crate::SDP_ATTRIBUTE_RID; pub(crate) struct PeerConnectionInternal {} @@ -573,7 +573,7 @@ impl PeerConnectionInternal { let (rsid_extension_id, _, _) = self .media_engine .get_header_extension_id(RTCRtpHeaderExtensionCapability { - uri: SDES_REPAIR_RTP_STREAM_ID_URI.to_owned(), + uri: ::sdp::extmap::SDES_REPAIR_RTP_STREAM_ID_URI.to_owned(), }) .await; @@ -701,8 +701,8 @@ impl PeerConnectionInternal { on_track_handler: Arc>>, ) { receiver.start(incoming).await; - for t in receiver.tracks().await { - if t.ssrc() == 0 { + for track in receiver.tracks().await { + if track.ssrc() == 0 { return; } @@ -710,31 +710,29 @@ impl PeerConnectionInternal { let transceiver = Arc::clone(&transceiver); let on_track_handler = Arc::clone(&on_track_handler); tokio::spawn(async move { - if let Some(track) = receiver.track().await { - let mut b = vec![0u8; receive_mtu]; - let pkt = match track.peek(&mut b).await { - Ok((pkt, _)) => pkt, - Err(err) => { - log::warn!( - "Could not determine PayloadType for SSRC {} ({})", - track.ssrc(), - err - ); - return; - } - }; - - if let Err(err) = track.check_and_update_track(&pkt).await { + let mut b = vec![0u8; receive_mtu]; + let pkt = match track.peek(&mut b).await { + Ok((pkt, _)) => pkt, + Err(err) => { log::warn!( - "Failed to set codec settings for track SSRC {} ({})", + "Could not determine PayloadType for SSRC {} ({})", track.ssrc(), err ); return; } + }; - RTCPeerConnection::do_track(on_track_handler, track, receiver, transceiver); + if let Err(err) = track.check_and_update_track(&pkt).await { + log::warn!( + "Failed to set codec settings for track SSRC {} ({})", + track.ssrc(), + err + ); + return; } + + RTCPeerConnection::do_track(on_track_handler, track, receiver, transceiver); }); } } diff --git a/rtc/src/peer_connection/sdp/mod.rs b/rtc/src/peer_connection/sdp/mod.rs index 8b42806..bf47d39 100644 --- a/rtc/src/peer_connection/sdp/mod.rs +++ b/rtc/src/peer_connection/sdp/mod.rs @@ -224,26 +224,20 @@ pub(crate) fn track_details_from_sdp( }; } + // If media line is using RTP Stream Identifier Source Description per RFC8851 + // we will need to override tracks, and remove ssrcs. + // This is in particular important for Firefox, as it uses both 'rid', 'simulcast' + // and 'a=ssrc' lines. let rids = get_rids(media); if !rids.is_empty() && !track_id.is_empty() && !stream_id.is_empty() { - let mut simulcast_track = TrackDetails { + tracks_in_media_section = vec![TrackDetails { mid: SmolStr::from(mid_value), kind: codec_type, stream_id: stream_id.to_owned(), id: track_id.to_owned(), - rids: vec![], + rids: rids.iter().map(|r| SmolStr::from(&r.id)).collect(), ..Default::default() - }; - for rid in &rids { - simulcast_track.rids.push(SmolStr::from(&rid.id)); - } - if simulcast_track.rids.len() == tracks_in_media_section.len() { - for track in &tracks_in_media_section { - simulcast_track.ssrcs.extend(&track.ssrcs) - } - } - - tracks_in_media_section = vec![simulcast_track]; + }]; } incoming_tracks.extend(tracks_in_media_section); diff --git a/rtc/src/rtp_transceiver/rtp_receiver/mod.rs b/rtc/src/rtp_transceiver/rtp_receiver/mod.rs index 0b526b2..53ac699 100644 --- a/rtc/src/rtp_transceiver/rtp_receiver/mod.rs +++ b/rtc/src/rtp_transceiver/rtp_receiver/mod.rs @@ -397,16 +397,6 @@ impl RTCRtpReceiver { } } - /// track returns the RtpTransceiver TrackRemote - pub async fn track(&self) -> Option> { - let tracks = self.internal.tracks.read().await; - if tracks.len() != 1 { - None - } else { - tracks.first().map(|t| Arc::clone(&t.track)) - } - } - /// tracks returns the RtpTransceiver traclockks /// A RTPReceiver to support Simulcast may now have multiple tracks pub async fn tracks(&self) -> Vec> { diff --git a/rtc/src/rtp_transceiver/rtp_receiver/rtp_receiver_test.rs b/rtc/src/rtp_transceiver/rtp_receiver/rtp_receiver_test.rs index 304bff8..7520667 100644 --- a/rtc/src/rtp_transceiver/rtp_receiver/rtp_receiver_test.rs +++ b/rtc/src/rtp_transceiver/rtp_receiver/rtp_receiver_test.rs @@ -92,36 +92,38 @@ async fn test_set_rtp_parameters() -> Result<()> { Box::pin(async move { receiver.set_rtp_parameters(P.clone()).await; - if let Some(t) = receiver.track().await { - let incoming_track_codecs = t.codec(); - - assert_eq!(P.header_extensions, t.params().header_extensions); - assert_eq!( - P.codecs[0].capability.mime_type, - incoming_track_codecs.capability.mime_type - ); - assert_eq!( - P.codecs[0].capability.clock_rate, - incoming_track_codecs.capability.clock_rate - ); - assert_eq!( - P.codecs[0].capability.channels, - incoming_track_codecs.capability.channels - ); - assert_eq!( - P.codecs[0].capability.sdp_fmtp_line, - incoming_track_codecs.capability.sdp_fmtp_line - ); - assert_eq!( - P.codecs[0].capability.rtcp_feedback, - incoming_track_codecs.capability.rtcp_feedback - ); - assert_eq!(P.codecs[0].payload_type, incoming_track_codecs.payload_type); - - { - let mut done = seen_packet_tx2.lock().await; - done.take(); - } + let tracks = receiver.tracks().await; + assert_eq!(tracks.len(), 1); + let t = tracks.first().unwrap(); + + let incoming_track_codecs = t.codec(); + + assert_eq!(P.header_extensions, t.params().header_extensions); + assert_eq!( + P.codecs[0].capability.mime_type, + incoming_track_codecs.capability.mime_type + ); + assert_eq!( + P.codecs[0].capability.clock_rate, + incoming_track_codecs.capability.clock_rate + ); + assert_eq!( + P.codecs[0].capability.channels, + incoming_track_codecs.capability.channels + ); + assert_eq!( + P.codecs[0].capability.sdp_fmtp_line, + incoming_track_codecs.capability.sdp_fmtp_line + ); + assert_eq!( + P.codecs[0].capability.rtcp_feedback, + incoming_track_codecs.capability.rtcp_feedback + ); + assert_eq!(P.codecs[0].payload_type, incoming_track_codecs.payload_type); + + { + let mut done = seen_packet_tx2.lock().await; + done.take(); } }) }));