Skip to content
File

Blob: firmware/vendor/str0m/src/pacer/control.rs

rust92 lines
1use crate::rtp_::Bitrate;
2 
3const PACING_FACTOR: f64 = 1.1;
4 
5/// Target padding rate when media is active. This maintains NAT bindings, RTX state,
6/// and allows ALR periodic probes to discover higher bandwidth.
7const PADDING_TARGET: Bitrate = Bitrate::bps(50_000);
8 
9pub(crate) struct PacingResult {
10 /// The bitrate at which the pacer may emit padding **when there is no media queued**.
11 ///
12 /// This value is intentionally an *absolute* target used by the pacer, not a “delta to add
13 /// on top of current media”. In practice the **effective padding** over time is the
14 /// difference between this target and the media actually sent, because padding is only used
15 /// to fill gaps (empty queues), not to continuously top-up while media is flowing.
16 pub padding_rate: Bitrate,
17 pub pacing_rate: Bitrate,
18}
19 
20/// Controls the pacing and padding rates.
21pub(crate) struct PacerControl {}
22 
23impl PacerControl {
24 pub fn new() -> Self {
25 Self {}
26 }
27 
28 pub fn calculate(
29 &self,
30 has_active_media: bool,
31 estimate: Bitrate,
32 is_overuse: bool,
33 ) -> PacingResult {
34 // ALR periodic probes handle bandwidth discovery, not continuous padding.
35 let padding_rate = if is_overuse {
36 // No padding during overuse
37 Bitrate::ZERO
38 } else if has_active_media {
39 // Pad to 50 kbps to maintain NAT bindings and RTX state
40 PADDING_TARGET
41 } else {
42 // No padding when no media is being sent
43 Bitrate::ZERO
44 };
45 
46 // Set pacing rate to smooth out media transmission (burst avoidance).
47 // Must be at least the current BWE estimate * factor, but also high enough
48 // to allow the padding we want to send.
49 let min_pacing_rate = estimate * PACING_FACTOR;
50 let pacing_rate = min_pacing_rate.max(padding_rate);
51 
52 PacingResult {
53 padding_rate,
54 pacing_rate,
55 }
56 }
57}
58 
59#[cfg(test)]
60mod test {
61 use super::*;
62 
63 #[test]
64 fn padding_enabled_with_active_media() {
65 let c = PacerControl::new();
66 let estimate = Bitrate::kbps(1_000);
67 
68 let r = c.calculate(true, estimate, false);
69 
70 assert_eq!(r.padding_rate, PADDING_TARGET);
71 }
72 
73 #[test]
74 fn no_padding_without_active_media() {
75 let c = PacerControl::new();
76 let estimate = Bitrate::kbps(1_000);
77 
78 let r = c.calculate(false, estimate, false);
79 
80 assert_eq!(r.padding_rate, Bitrate::ZERO);
81 }
82 
83 #[test]
84 fn overuse_suppresses_padding() {
85 let c = PacerControl::new();
86 let estimate = Bitrate::mbps(40);
87 
88 let r = c.calculate(true, estimate, true);
89 assert_eq!(r.padding_rate, Bitrate::ZERO);
90 }
91}