Skip to content

Commit 1b5b973

Browse files
committed
Pause in TrackBinding when direction is not send
When direction is such that we are not sending. The writing of RTP packets is stopped already in TrackBinding to avoid allocating sequence numbers when they are not needed.
1 parent 0c35e61 commit 1b5b973

File tree

4 files changed

+66
-1
lines changed

4 files changed

+66
-1
lines changed

webrtc/src/rtp_transceiver/rtp_sender/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ impl RTCRtpSender {
332332
.await,
333333
ssrc: context.ssrc,
334334
write_stream: context.write_stream.clone(),
335+
paused: self.paused.clone(),
335336
};
336337

337338
t.bind(&new_context).await
@@ -392,6 +393,7 @@ impl RTCRtpSender {
392393
write_stream: Some(
393394
Arc::clone(&write_stream) as Arc<dyn TrackLocalWriter + Send + Sync>
394395
),
396+
paused: self.paused.clone(),
395397
};
396398

397399
let codec = if let Some(t) = &*track {

webrtc/src/track/track_local/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ pub struct TrackLocalContext {
3535
pub(crate) params: RTCRtpParameters,
3636
pub(crate) ssrc: SSRC,
3737
pub(crate) write_stream: Option<Arc<dyn TrackLocalWriter + Send + Sync>>,
38+
pub(crate) paused: Arc<AtomicBool>,
3839
}
3940

4041
impl TrackLocalContext {
@@ -104,6 +105,13 @@ pub(crate) struct TrackBinding {
104105
ssrc: SSRC,
105106
payload_type: PayloadType,
106107
write_stream: Option<Arc<dyn TrackLocalWriter + Send + Sync>>,
108+
paused: Arc<AtomicBool>,
109+
}
110+
111+
impl TrackBinding {
112+
pub fn is_paused(&self) -> bool {
113+
self.paused.load(Ordering::SeqCst)
114+
}
107115
}
108116

109117
pub(crate) struct InterceptorToTrackLocalWriter {
@@ -118,6 +126,10 @@ impl InterceptorToTrackLocalWriter {
118126
paused,
119127
}
120128
}
129+
130+
fn is_paused(&self) -> bool {
131+
self.paused.load(Ordering::SeqCst)
132+
}
121133
}
122134

123135
impl std::fmt::Debug for InterceptorToTrackLocalWriter {
@@ -129,7 +141,7 @@ impl std::fmt::Debug for InterceptorToTrackLocalWriter {
129141
#[async_trait]
130142
impl TrackLocalWriter for InterceptorToTrackLocalWriter {
131143
async fn write_rtp(&self, pkt: &rtp::packet::Packet) -> Result<usize> {
132-
if self.paused.load(Ordering::SeqCst) {
144+
if self.is_paused() {
133145
return Ok(0);
134146
}
135147

webrtc/src/track/track_local/track_local_static_rtp.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,16 @@ impl TrackLocalStaticRTP {
2828
pub fn codec(&self) -> RTCRtpCodecCapability {
2929
self.codec.clone()
3030
}
31+
32+
pub async fn any_binding_paused(&self) -> bool {
33+
let bindings = self.bindings.lock().await;
34+
bindings.iter().any(|b| b.paused.load(Ordering::SeqCst))
35+
}
36+
37+
pub async fn all_binding_paused(&self) -> bool {
38+
let bindings = self.bindings.lock().await;
39+
bindings.iter().all(|b| b.paused.load(Ordering::SeqCst))
40+
}
3141
}
3242

3343
#[async_trait]
@@ -50,6 +60,7 @@ impl TrackLocal for TrackLocalStaticRTP {
5060
payload_type: codec.payload_type,
5161
write_stream: t.write_stream(),
5262
id: t.id(),
63+
paused: t.paused.clone(),
5364
}));
5465
}
5566

@@ -122,6 +133,9 @@ impl TrackLocalWriter for TrackLocalStaticRTP {
122133
bindings.clone()
123134
};
124135
for b in bindings {
136+
if b.is_paused() {
137+
continue;
138+
}
125139
pkt.header.ssrc = b.ssrc;
126140
pkt.header.payload_type = b.payload_type;
127141
if let Some(write_stream) = &b.write_stream {

webrtc/src/track/track_local/track_local_static_sample.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::*;
33
use crate::error::flatten_errs;
44

55
use crate::track::RTP_OUTBOUND_MTU;
6+
use log::warn;
67
use media::Sample;
78
use tokio::sync::Mutex;
89

@@ -11,6 +12,7 @@ struct TrackLocalStaticSampleInternal {
1112
packetizer: Option<Box<dyn rtp::packetizer::Packetizer + Send + Sync>>,
1213
sequencer: Option<Box<dyn rtp::sequence::Sequencer + Send + Sync>>,
1314
clock_rate: f64,
15+
did_warn_about_wonky_pause: bool,
1416
}
1517

1618
/// TrackLocalStaticSample is a TrackLocal that has a pre-set codec and accepts Samples.
@@ -32,6 +34,7 @@ impl TrackLocalStaticSample {
3234
packetizer: None,
3335
sequencer: None,
3436
clock_rate: 0.0f64,
37+
did_warn_about_wonky_pause: false,
3538
}),
3639
}
3740
}
@@ -52,6 +55,40 @@ impl TrackLocalStaticSample {
5255
return Ok(());
5356
}
5457

58+
let (any_paused, all_paused) = (
59+
self.rtp_track.any_binding_paused().await,
60+
self.rtp_track.all_binding_paused().await,
61+
);
62+
63+
if all_paused {
64+
// Abort already here to not increment sequence numbers.
65+
return Ok(());
66+
}
67+
68+
if any_paused {
69+
// This is a problem state due to how this impl is structured. The sequencer will allocate
70+
// one sequence number per RTP packet regardless of how many TrackBinding that will send
71+
// the packet. I.e. we get the same sequence number per multiple SSRC, which is not good
72+
// for SRTP, but that's how it works.
73+
//
74+
// Chrome has further a problem with regards to jumps in sequence number. Consider this:
75+
//
76+
// 1. Create track local
77+
// 2. Bind track local to track 1.
78+
// 3. Bind track local to track 2.
79+
// 4. Pause track 1.
80+
// 5. Keep sending...
81+
//
82+
// At this point, the track local will keep incrementing the sequence number, because we have
83+
// one binding that is still active. However Chrome can only accept a relatively small jump
84+
// in SRTP key deriving, which means if this pause state of one binding persists for a longer
85+
// time, the track can never be resumed (against Chrome).
86+
if !internal.did_warn_about_wonky_pause {
87+
internal.did_warn_about_wonky_pause = true;
88+
warn!("Detected multiple track bindings where only one was paused");
89+
}
90+
}
91+
5592
// skip packets by the number of previously dropped packets
5693
if let Some(sequencer) = &internal.sequencer {
5794
for _ in 0..sample.prev_dropped_packets {

0 commit comments

Comments
 (0)