Skip to content
File

Blob: firmware/vendor/str0m/tests/app-specific-feedback.rs

rust214 lines
1use std::sync::Arc;
2use std::time::Duration;
3 
4use str0m::media::MediaKind;
5use str0m::rtp::Ssrc;
6use str0m::{Event, RtcError};
7 
8mod common;
9use common::{connect_l_r, init_crypto_default, init_log, progress};
10 
11/// Test that AppSpecificFeedback sent from one peer via DirectApi
12/// is received by the other peer as an Event::AppSpecificFeedback.
13#[test]
14pub fn app_specific_feedback_direct_api() -> Result<(), RtcError> {
15 init_log();
16 init_crypto_default();
17 
18 let (mut l, mut r) = connect_l_r();
19 
20 // Declare a video media line on both sides so we have valid SSRCs
21 // for routing the feedback.
22 let mid = "vid".into();
23 let ssrc_l: Ssrc = 100.into();
24 let ssrc_r: Ssrc = 200.into();
25 
26 l.direct_api().declare_media(mid, MediaKind::Video);
27 l.direct_api().declare_stream_tx(ssrc_l, None, mid, None);
28 l.direct_api().expect_stream_rx(ssrc_r, None, mid, None);
29 
30 r.direct_api().declare_media(mid, MediaKind::Video);
31 r.direct_api().declare_stream_tx(ssrc_r, None, mid, None);
32 r.direct_api().expect_stream_rx(ssrc_l, None, mid, None);
33 
34 // Sync clocks
35 let max = l.last.max(r.last);
36 l.last = max;
37 r.last = max;
38 
39 // Build a test payload โ€” a simple "TestAppFeedback" message.
40 let test_payload: Vec<u8> = vec![
41 0x54, 0x46, // magic: "TF" (TestFeedback)
42 0x00, 0x01, // version: 1
43 0xDE, 0xAD, 0xBE, 0xEF, // application data
44 0xCA, 0xFE, 0xBA, 0xBE, // more application data
45 ];
46 
47 // L sends AppSpecificFeedback to R
48 l.direct_api().send_app_specific_feedback(
49 ssrc_l, // sender_ssrc
50 ssrc_r, // media_ssrc
51 test_payload.clone(),
52 );
53 
54 // Progress until R receives the feedback event
55 let deadline = l.last + Duration::from_secs(5);
56 let mut received = false;
57 
58 loop {
59 if l.last > deadline || r.last > deadline {
60 break;
61 }
62 progress(&mut l, &mut r)?;
63 
64 // Check R's events for the feedback
65 for (_time, event) in r.events.drain(..) {
66 if let Event::AppSpecificFeedback(fb) = event {
67 assert_eq!(fb.sender_ssrc, ssrc_l);
68 assert_eq!(fb.media_ssrc, ssrc_r);
69 assert_eq!(&fb.payload[..test_payload.len()], &test_payload[..]);
70 received = true;
71 }
72 }
73 
74 if received {
75 break;
76 }
77 }
78 
79 assert!(
80 received,
81 "R should have received AppSpecificFeedback from L"
82 );
83 
84 Ok(())
85}
86 
87/// Test bidirectional AppSpecificFeedback โ€” both peers send and receive.
88#[test]
89pub fn app_specific_feedback_bidirectional() -> Result<(), RtcError> {
90 init_log();
91 init_crypto_default();
92 
93 let (mut l, mut r) = connect_l_r();
94 
95 let mid = "vid".into();
96 let ssrc_l: Ssrc = 100.into();
97 let ssrc_r: Ssrc = 200.into();
98 
99 l.direct_api().declare_media(mid, MediaKind::Video);
100 l.direct_api().declare_stream_tx(ssrc_l, None, mid, None);
101 l.direct_api().expect_stream_rx(ssrc_r, None, mid, None);
102 
103 r.direct_api().declare_media(mid, MediaKind::Video);
104 r.direct_api().declare_stream_tx(ssrc_r, None, mid, None);
105 r.direct_api().expect_stream_rx(ssrc_l, None, mid, None);
106 
107 let max = l.last.max(r.last);
108 l.last = max;
109 r.last = max;
110 
111 let payload_l_to_r: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
112 let payload_r_to_l: Vec<u8> = vec![0xAA, 0xBB, 0xCC, 0xDD];
113 
114 // Both sides send feedback
115 l.direct_api()
116 .send_app_specific_feedback(ssrc_l, ssrc_r, payload_l_to_r.clone());
117 r.direct_api()
118 .send_app_specific_feedback(ssrc_r, ssrc_l, payload_r_to_l.clone());
119 
120 let deadline = l.last + Duration::from_secs(5);
121 let mut r_received = false;
122 let mut l_received = false;
123 
124 loop {
125 if (r_received && l_received) || l.last > deadline || r.last > deadline {
126 break;
127 }
128 progress(&mut l, &mut r)?;
129 
130 for (_time, event) in r.events.drain(..) {
131 if let Event::AppSpecificFeedback(fb) = event {
132 assert_eq!(&fb.payload[..payload_l_to_r.len()], &payload_l_to_r[..]);
133 r_received = true;
134 }
135 }
136 
137 for (_time, event) in l.events.drain(..) {
138 if let Event::AppSpecificFeedback(fb) = event {
139 assert_eq!(&fb.payload[..payload_r_to_l.len()], &payload_r_to_l[..]);
140 l_received = true;
141 }
142 }
143 }
144 
145 assert!(r_received, "R should have received feedback from L");
146 assert!(l_received, "L should have received feedback from R");
147 
148 Ok(())
149}
150 
151/// Test that multiple AppSpecificFeedback messages are delivered in order.
152#[test]
153pub fn app_specific_feedback_multiple_messages() -> Result<(), RtcError> {
154 init_log();
155 init_crypto_default();
156 
157 let (mut l, mut r) = connect_l_r();
158 
159 let mid = "vid".into();
160 let ssrc_l: Ssrc = 100.into();
161 let ssrc_r: Ssrc = 200.into();
162 
163 l.direct_api().declare_media(mid, MediaKind::Video);
164 l.direct_api().declare_stream_tx(ssrc_l, None, mid, None);
165 l.direct_api().expect_stream_rx(ssrc_r, None, mid, None);
166 
167 r.direct_api().declare_media(mid, MediaKind::Video);
168 r.direct_api().declare_stream_tx(ssrc_r, None, mid, None);
169 r.direct_api().expect_stream_rx(ssrc_l, None, mid, None);
170 
171 let max = l.last.max(r.last);
172 l.last = max;
173 r.last = max;
174 
175 // Send 3 messages sequentially โ€” at most one pending at a time.
176 let mut received_payloads: Vec<Arc<[u8]>> = Vec::new();
177 
178 for i in 0u8..3 {
179 let payload = vec![i, i + 10, i + 20, i + 30];
180 l.direct_api()
181 .send_app_specific_feedback(ssrc_l, ssrc_r, payload);
182 
183 let deadline = l.last + Duration::from_secs(5);
184 loop {
185 if l.last > deadline || r.last > deadline {
186 break;
187 }
188 progress(&mut l, &mut r)?;
189 
190 let mut found = false;
191 for (_time, event) in r.events.drain(..) {
192 if let Event::AppSpecificFeedback(fb) = event {
193 received_payloads.push(fb.payload);
194 found = true;
195 }
196 }
197 if found {
198 break;
199 }
200 }
201 }
202 
203 assert_eq!(received_payloads.len(), 3, "Should receive all 3 messages");
204 for (i, payload) in received_payloads.iter().enumerate() {
205 let i = i as u8;
206 assert_eq!(payload[0], i);
207 assert_eq!(payload[1], i + 10);
208 assert_eq!(payload[2], i + 20);
209 assert_eq!(payload[3], i + 30);
210 }
211 
212 Ok(())
213}