Skip to content
File

Blob: firmware/vendor/str0m/tests/bwe/alr.rs

rust237 lines
1//! BWE test for allocation probing mechanics when entering ALR.
2 
3use std::sync::Arc;
4use std::time::Duration;
5 
6use netem::{DataSize, NetemConfig};
7use str0m::RtcError;
8use str0m::bwe::Bitrate;
9 
10use crate::common::{BweTestContext, Step, connect_with_bwe, init_crypto_default, init_log};
11 
12#[test]
13pub fn bwe_allocation_probe_on_desired_increase_in_alr() -> Result<(), RtcError> {
14 init_log();
15 init_crypto_default();
16 
17 // Start with lower max_bitrate, enter ALR, then increase desired
18 let mut plan = alr_preamble_steps(Bitrate::mbps(3));
19 plan.extend(enter_alr_steps(Bitrate::mbps(3)));
20 plan.extend(vec![
21 Step::CheckProbe {
22 description: "First periodic ALR probe",
23 check: Arc::new(|_index, probe| probe.is_alr_probe()),
24 },
25 // Now increase desired bitrate while in ALR - should trigger IncreaseAlr probes
26 Step::Media {
27 description: "Increase desired bitrate while in ALR",
28 desired_bitrate: Bitrate::mbps(5), // Increased from 3 to 5
29 media_send_rate: Bitrate::kbps(500), // Stay in ALR
30 },
31 Step::Run {
32 description: "Allow probe to be triggered",
33 duration: Duration::from_millis(100),
34 },
35 Step::CheckProbe {
36 description: "Allocation probe triggered by desired increase",
37 check: Arc::new(|_index, probe| probe.is_alr_probe()),
38 },
39 ]);
40 
41 let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(2), Bitrate::mbps(3));
42 let mut ctx = BweTestContext::new(&mut l, &mut r);
43 ctx.run_plan(&mut l, &mut r, &plan)?;
44 
45 Ok(())
46}
47 
48#[test]
49pub fn bwe_periodic_allocation_probing_in_alr() -> Result<(), RtcError> {
50 init_log();
51 init_crypto_default();
52 
53 let mut plan = alr_setup_steps(Bitrate::mbps(5));
54 plan.extend(vec![
55 // First allocation probe on ALR entry
56 Step::CheckProbe {
57 description: "First allocation probe on ALR entry",
58 check: Arc::new(|_index, probe| probe.is_alr_probe()),
59 },
60 // Wait for periodic probe interval (MIN_TIME_BETWEEN_ALR_PROBES = 5 seconds)
61 Step::Run {
62 description: "Wait 6 seconds for periodic probe",
63 duration: Duration::from_secs(6),
64 },
65 // Should see another allocation probe after 5 seconds
66 Step::CheckProbe {
67 description: "Periodic allocation probe fires after 5 seconds",
68 check: Arc::new(|_index, probe| probe.is_alr_probe()),
69 },
70 ]);
71 
72 let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(2), Bitrate::mbps(5));
73 let mut ctx = BweTestContext::new(&mut l, &mut r);
74 ctx.run_plan(&mut l, &mut r, &plan)?;
75 
76 Ok(())
77}
78 
79#[test]
80pub fn bwe_no_allocation_probing_when_estimate_at_max() -> Result<(), RtcError> {
81 init_log();
82 init_crypto_default();
83 
84 let plan = vec![
85 Step::Conditions {
86 description: "Moderate bandwidth network",
87 config: NetemConfig::new()
88 .latency(Duration::from_millis(10))
89 .jitter(Duration::from_millis(2))
90 .link(Bitrate::mbps(3), DataSize::kbytes(100))
91 .seed(42),
92 },
93 // Start with bitrate close to max desired
94 Step::Media {
95 description: "Start at 1.5 Mbps, desire 2 Mbps",
96 desired_bitrate: Bitrate::mbps(2),
97 media_send_rate: Bitrate::mbps(1),
98 },
99 // Let estimate grow to near max
100 Step::Run {
101 description: "Grow to desired bitrate",
102 duration: Duration::from_secs(10),
103 },
104 Step::Check {
105 description: "Estimate should reach desired",
106 at_least: Bitrate::mbps(1),
107 },
108 // Enter ALR with estimate >= max_bitrate
109 Step::Media {
110 description: "Enter ALR with estimate at max",
111 desired_bitrate: Bitrate::mbps(2),
112 media_send_rate: Bitrate::kbps(500),
113 },
114 // Note: We can't easily test ABSENCE of probes with current CheckProbe mechanism
115 // Instead, we verify estimate stays stable without ALR probing
116 Step::Run {
117 description: "Wait and verify no growth from allocation probes",
118 duration: Duration::from_secs(6),
119 },
120 Step::Check {
121 description: "Estimate stable around max bitrate",
122 at_least: Bitrate::mbps(1),
123 },
124 ];
125 
126 let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(1), Bitrate::mbps(2));
127 
128 let mut ctx = BweTestContext::new(&mut l, &mut r);
129 
130 ctx.run_plan(&mut l, &mut r, &plan)?;
131 
132 Ok(())
133}
134 
135#[test]
136fn alr_exit_has_hysteresis() -> Result<(), RtcError> {
137 init_log();
138 init_crypto_default();
139 
140 let mut plan = alr_setup_steps(Bitrate::mbps(5));
141 plan.extend(vec![
142 Step::CheckProbe {
143 description: "First periodic ALR probe",
144 check: Arc::new(|_index, probe| probe.is_alr_probe()),
145 },
146 // Increase send rate to the hysteresis gap (between entry and exit thresholds)
147 // Entry: ratio > 0.80 (utilization < 20%)
148 // Exit: ratio < 0.50 (utilization > 50%)
149 // Gap: 0.50-0.80 ratio (20-50% utilization) - should STAY in ALR
150 Step::Media {
151 description: "Increase to ~35% utilization (in hysteresis gap)",
152 desired_bitrate: Bitrate::mbps(5),
153 media_send_rate: Bitrate::mbps(1), // ~35% of 3 Mbps estimate
154 },
155 Step::Run {
156 description: "Wait over 500ms window for ALR check",
157 duration: Duration::from_secs(1),
158 },
159 // Should still be in ALR - periodic probes should continue
160 Step::Run {
161 description: "Wait for periodic probe (should still be in ALR)",
162 duration: Duration::from_secs(5),
163 },
164 Step::CheckProbe {
165 description: "Periodic ALR probe confirms still in ALR",
166 check: Arc::new(|_index, probe| probe.is_alr_probe()),
167 },
168 // Now increase above exit threshold to confirm we eventually exit
169 Step::Media {
170 description: "Increase to 60% utilization (above exit threshold)",
171 desired_bitrate: Bitrate::mbps(5),
172 media_send_rate: Bitrate::mbps(2), // ~60% of 3 Mbps estimate
173 },
174 Step::Run {
175 description: "Wait for ALR exit",
176 duration: Duration::from_secs(2),
177 },
178 // Test completes - we've verified hysteresis by staying in ALR in the gap
179 ]);
180 
181 let (mut l, mut r) = connect_with_bwe(Bitrate::mbps(2), Bitrate::mbps(5));
182 let mut ctx = BweTestContext::new(&mut l, &mut r);
183 ctx.run_plan(&mut l, &mut r, &plan)?;
184 
185 Ok(())
186}
187 
188/// Common setup steps for ALR tests: establish connection, wait for probes to complete,
189/// then enter ALR with low send rate. Tests can append their specific scenarios.
190fn alr_setup_steps(max_bitrate: Bitrate) -> Vec<Step> {
191 let mut plan = alr_preamble_steps(max_bitrate);
192 plan.extend(enter_alr_steps(max_bitrate));
193 plan
194}
195 
196/// Common ALR test preamble: establish connection and allow initial probing to settle
197/// without entering ALR.
198fn alr_preamble_steps(max_bitrate: Bitrate) -> Vec<Step> {
199 vec![
200 Step::Conditions {
201 description: "Moderate bandwidth network",
202 config: NetemConfig::new()
203 .link(Bitrate::mbps(3), DataSize::kbytes(100))
204 .seed(42),
205 },
206 Step::Media {
207 description: "Start with 2 Mbps to avoid early ALR",
208 desired_bitrate: max_bitrate,
209 media_send_rate: Bitrate::mbps(2), // Higher rate prevents ALR during initial probes
210 },
211 Step::Run {
212 description: "Wait for initial probes to complete",
213 duration: Duration::from_secs(2),
214 },
215 ]
216}
217 
218/// Enter ALR and give the ALR detector time to latch.
219fn enter_alr_steps(max_bitrate: Bitrate) -> Vec<Step> {
220 vec![
221 Step::Media {
222 description: "Enter ALR with low send rate",
223 desired_bitrate: max_bitrate,
224 media_send_rate: Bitrate::kbps(500),
225 },
226 Step::Run {
227 description: "Allow ALR detection",
228 duration: Duration::from_secs(1),
229 },
230 // No probe on ALR entry - wait for first periodic probe (5s after last probe)
231 Step::Run {
232 description: "Wait for first periodic ALR probe",
233 duration: Duration::from_secs(5),
234 },
235 ]
236}