Skip to content

Commit bfef3e4

Browse files
committed
exponential backoff FIR requests
1 parent befb323 commit bfef3e4

File tree

3 files changed

+35
-14
lines changed

3 files changed

+35
-14
lines changed

pulsebeam/src/participant/downstream/video.rs

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -415,7 +415,7 @@ struct Slot {
415415
switcher: Switcher,
416416
state: Option<SlotState>,
417417
switching_started_at: Option<Instant>,
418-
keyframe_req_count: u32,
418+
keyframe_retries: usize,
419419
waker: Option<Waker>,
420420
}
421421

@@ -427,7 +427,7 @@ impl Slot {
427427
switcher: Switcher::new(rtp::VIDEO_FREQUENCY),
428428
state: Some(SlotState::Idle),
429429
switching_started_at: None,
430-
keyframe_req_count: 0,
430+
keyframe_retries: 0,
431431
waker: None,
432432
}
433433
}
@@ -472,7 +472,7 @@ impl Slot {
472472
receiver.channel.reset();
473473
receiver.request_keyframe(KeyframeRequestKind::Fir);
474474
self.switching_started_at = Some(Instant::now());
475-
self.keyframe_req_count = 1;
475+
self.keyframe_retries = 0;
476476

477477
tracing::info!(
478478
mid = %self.mid,
@@ -549,32 +549,45 @@ impl Slot {
549549
}
550550

551551
fn poll_slow(&mut self, now: Instant) {
552+
const KEYFRAME_RETRY_DELAYS_MS: [u64; 4] = [500, 1000, 2000, 4000];
553+
554+
// Chrome shares keyframe request throttling for all simulcast streams &
555+
// Our keyframe request might get lost in the middle. Retry some to at least
556+
// reduce the probability to miss the keyframe.
552557
let Some(started_at) = self.switching_started_at else {
553558
return;
554559
};
555560

556-
if self.keyframe_req_count >= 5 {
561+
if self.keyframe_retries >= KEYFRAME_RETRY_DELAYS_MS.len() {
557562
return;
558563
}
559564

560-
let deadline = started_at + Duration::from_secs(1) * self.keyframe_req_count;
565+
let current_delay_ms = KEYFRAME_RETRY_DELAYS_MS[self.keyframe_retries];
566+
let deadline = started_at + Duration::from_millis(current_delay_ms);
561567
if deadline > now {
562568
return;
563569
}
564570

565-
self.keyframe_req_count += 1;
566-
let Some(receiver) = self.target_receiver() else {
567-
return;
568-
};
569-
receiver.request_keyframe(KeyframeRequestKind::Fir);
571+
self.keyframe_retries += 1;
572+
if let Some(receiver) = self.target_receiver() {
573+
tracing::warn!(
574+
receiver = %receiver,
575+
"Switch slow. Retrying keyframe request (attempt {}/{}). Elapsed: {:?}",
576+
self.keyframe_retries,
577+
KEYFRAME_RETRY_DELAYS_MS.len(),
578+
now.duration_since(started_at)
579+
);
580+
581+
receiver.request_keyframe(KeyframeRequestKind::Fir);
582+
}
570583
}
571584

572585
#[inline]
573586
fn transition_to(&mut self, new_state: SlotState) {
574587
match &new_state {
575588
SlotState::Streaming { .. } => {
576589
self.switching_started_at = None;
577-
self.keyframe_req_count = 0;
590+
self.keyframe_retries = 0;
578591
}
579592
_ => {}
580593
}

pulsebeam/src/rtp/monitor.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -591,11 +591,8 @@ impl DeltaDeltaState {
591591
}
592592

593593
// Check if there's space in the buffer for this packet
594-
// Using wrapping arithmetic: offset < capacity means it's in range
595594
let offset_from_tail = seq_val.wrapping_sub(tail_val);
596595
if offset_from_tail >= buffer_capacity {
597-
// No space - need to slide the window
598-
// process_until is now optimized to only check each buffer slot once
599596
let new_tail = self.head.wrapping_sub(buffer_capacity);
600597
self.process_until(new_tail.into());
601598
}

pulsebeam/src/track.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use std::fmt::Display;
12
use std::pin::Pin;
23
use std::{
34
sync::Arc,
@@ -58,6 +59,16 @@ pub struct SimulcastReceiver {
5859
pub state: StreamState,
5960
}
6061

62+
impl Display for SimulcastReceiver {
63+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64+
f.write_fmt(format_args!(
65+
"{}:{}",
66+
self.meta.id,
67+
self.rid.as_deref().unwrap_or("_")
68+
))
69+
}
70+
}
71+
6172
impl SimulcastReceiver {
6273
pub fn request_keyframe(&self, kind: KeyframeRequestKind) {
6374
if let Err(err) = self.keyframe_requester.try_send(kind) {

0 commit comments

Comments
 (0)