Skip to content
File

Blob: firmware/vendor/str0m/tests/keyframe-requests.rs

rust209 lines
1//! Tests for PLI/FIR keyframe request handling.
2 
3use std::net::Ipv4Addr;
4 
5use str0m::media::{Direction, KeyframeRequestKind, MediaKind};
6use str0m::{Event, RtcError};
7 
8mod common;
9use common::{Peer, TestRtc, init_crypto_default, init_log, negotiate, progress};
10 
11/// Test PLI (Picture Loss Indication) request is sent and received.
12#[test]
13fn keyframe_request_pli() -> Result<(), RtcError> {
14 init_log();
15 init_crypto_default();
16 
17 let mut l = TestRtc::new(Peer::Left);
18 let mut r = TestRtc::new(Peer::Right);
19 
20 l.add_host_candidate((Ipv4Addr::new(1, 1, 1, 1), 1000).into());
21 r.add_host_candidate((Ipv4Addr::new(2, 2, 2, 2), 2000).into());
22 
23 // L sends video to R
24 let mid = negotiate(&mut l, &mut r, |change| {
25 change.add_media(MediaKind::Video, Direction::SendRecv, None, None, None)
26 });
27 
28 loop {
29 if l.is_connected() && r.is_connected() {
30 break;
31 }
32 progress(&mut l, &mut r)?;
33 }
34 
35 let max = l.last.max(r.last);
36 l.last = max;
37 r.last = max;
38 
39 // Send video from L
40 let params = l.params_vp8();
41 let pt = params.pt();
42 
43 for i in 0..20 {
44 let wallclock = l.start + l.duration();
45 let time = l.duration().into();
46 l.writer(mid)
47 .unwrap()
48 .write(pt, wallclock, time, vec![0x10, 0x00, 0x00, i as u8])?;
49 progress(&mut l, &mut r)?;
50 }
51 
52 // R requests a keyframe via PLI
53 if let Some(mut writer) = r.writer(mid) {
54 if writer.is_request_keyframe_possible(KeyframeRequestKind::Pli) {
55 writer.request_keyframe(None, KeyframeRequestKind::Pli)?;
56 }
57 }
58 
59 // Progress until L receives the keyframe request
60 let mut found_keyframe_request = false;
61 for _ in 0..100 {
62 progress(&mut l, &mut r)?;
63 
64 for (_, event) in &l.events {
65 if let Event::KeyframeRequest(req) = event {
66 if req.mid == mid && req.kind == KeyframeRequestKind::Pli {
67 found_keyframe_request = true;
68 break;
69 }
70 }
71 }
72 
73 if found_keyframe_request {
74 break;
75 }
76 }
77 
78 assert!(
79 found_keyframe_request,
80 "L should receive a PLI keyframe request from R"
81 );
82 
83 Ok(())
84}
85 
86/// Test FIR (Full Intra Request) is sent and received.
87#[test]
88fn keyframe_request_fir() -> Result<(), RtcError> {
89 init_log();
90 init_crypto_default();
91 
92 let mut l = TestRtc::new(Peer::Left);
93 let mut r = TestRtc::new(Peer::Right);
94 
95 l.add_host_candidate((Ipv4Addr::new(1, 1, 1, 1), 1000).into());
96 r.add_host_candidate((Ipv4Addr::new(2, 2, 2, 2), 2000).into());
97 
98 let mid = negotiate(&mut l, &mut r, |change| {
99 change.add_media(MediaKind::Video, Direction::SendRecv, None, None, None)
100 });
101 
102 loop {
103 if l.is_connected() && r.is_connected() {
104 break;
105 }
106 progress(&mut l, &mut r)?;
107 }
108 
109 let max = l.last.max(r.last);
110 l.last = max;
111 r.last = max;
112 
113 // Send video from L
114 let params = l.params_vp8();
115 let pt = params.pt();
116 
117 for i in 0..20 {
118 let wallclock = l.start + l.duration();
119 let time = l.duration().into();
120 l.writer(mid)
121 .unwrap()
122 .write(pt, wallclock, time, vec![0x10, 0x00, 0x00, i as u8])?;
123 progress(&mut l, &mut r)?;
124 }
125 
126 // R requests a keyframe via FIR
127 if let Some(mut writer) = r.writer(mid) {
128 if writer.is_request_keyframe_possible(KeyframeRequestKind::Fir) {
129 writer.request_keyframe(None, KeyframeRequestKind::Fir)?;
130 }
131 }
132 
133 let mut found_keyframe_request = false;
134 for _ in 0..100 {
135 progress(&mut l, &mut r)?;
136 
137 for (_, event) in &l.events {
138 if let Event::KeyframeRequest(req) = event {
139 if req.mid == mid && req.kind == KeyframeRequestKind::Fir {
140 found_keyframe_request = true;
141 break;
142 }
143 }
144 }
145 
146 if found_keyframe_request {
147 break;
148 }
149 }
150 
151 assert!(
152 found_keyframe_request,
153 "L should receive a FIR keyframe request from R"
154 );
155 
156 Ok(())
157}
158 
159/// Test is_request_keyframe_possible() method.
160#[test]
161fn keyframe_request_possibility_check() -> Result<(), RtcError> {
162 init_log();
163 init_crypto_default();
164 
165 let mut l = TestRtc::new(Peer::Left);
166 let mut r = TestRtc::new(Peer::Right);
167 
168 l.add_host_candidate((Ipv4Addr::new(1, 1, 1, 1), 1000).into());
169 r.add_host_candidate((Ipv4Addr::new(2, 2, 2, 2), 2000).into());
170 
171 let mid = negotiate(&mut l, &mut r, |change| {
172 change.add_media(MediaKind::Video, Direction::SendRecv, None, None, None)
173 });
174 
175 loop {
176 if l.is_connected() && r.is_connected() {
177 break;
178 }
179 progress(&mut l, &mut r)?;
180 }
181 
182 // Send some video to establish the stream
183 let params = l.params_vp8();
184 let pt = params.pt();
185 
186 for i in 0..5 {
187 let wallclock = l.start + l.duration();
188 let time = l.duration().into();
189 l.writer(mid)
190 .unwrap()
191 .write(pt, wallclock, time, vec![0x10, 0x00, 0x00, i as u8])?;
192 progress(&mut l, &mut r)?;
193 }
194 
195 // Check that keyframe requests are possible
196 if let Some(writer) = r.writer(mid) {
197 let pli_possible = writer.is_request_keyframe_possible(KeyframeRequestKind::Pli);
198 let fir_possible = writer.is_request_keyframe_possible(KeyframeRequestKind::Fir);
199 
200 // At least one should be possible with default config
201 assert!(
202 pli_possible || fir_possible,
203 "At least PLI or FIR should be possible"
204 );
205 }
206 
207 Ok(())
208}