1use crate::Interceptor;
4use crate::{Attribute, Packet, StreamInfo, TaggedPacket};
5use sansio::Protocol;
6use shared::error::Error;
7use std::collections::VecDeque;
8use std::time::Instant;
9
10#[derive(Default)]
54pub struct NoopInterceptor {
55 read_queue: VecDeque<TaggedPacket>,
56 write_queue: VecDeque<TaggedPacket>,
57}
58
59impl NoopInterceptor {
60 pub fn new() -> Self {
62 Self::default()
63 }
64}
65
66impl Protocol<TaggedPacket, TaggedPacket, ()> for NoopInterceptor {
67 type Rout = TaggedPacket;
68 type Wout = TaggedPacket;
69 type Eout = ();
70 type Error = Error;
71 type Time = Instant;
72
73 fn handle_read(&mut self, mut msg: TaggedPacket) -> Result<(), Self::Error> {
74 if matches!(msg.message.packet, Packet::Rtp(_)) {
76 self.read_queue.push_back(msg);
77 return Ok(());
78 }
79
80 if msg.message.has(&Attribute::DeliverToApplication) {
92 self.read_queue.push_back(msg);
93 } else if !msg.message.attributes.is_empty() {
94 msg.message.packet = Packet::Rtcp(Vec::new());
95 self.read_queue.push_back(msg);
96 }
97 Ok(())
98 }
99
100 fn poll_read(&mut self) -> Option<Self::Rout> {
101 self.read_queue.pop_front()
102 }
103
104 fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
105 self.write_queue.push_back(msg);
106 Ok(())
107 }
108
109 fn poll_write(&mut self) -> Option<Self::Wout> {
110 self.write_queue.pop_front()
111 }
112}
113
114impl Interceptor for NoopInterceptor {
115 fn bind_local_stream(&mut self, _info: &StreamInfo) {}
116 fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
117 fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
118 fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use crate::{AttributedPacket, Registry, Slot, StreamInfo};
125 use sansio::Protocol;
126 use shared::TransportContext;
127 use shared::error::Error;
128 use std::collections::VecDeque;
129 use std::time::Instant;
130
131 fn packet(message: Packet) -> TaggedPacket {
132 TaggedPacket {
133 now: Instant::now(),
134 transport: TransportContext::default(),
135 message: AttributedPacket::new(message),
136 }
137 }
138
139 #[test]
140 fn inbound_rtcp_does_not_reach_the_application() {
141 let mut chain = Registry::new().build();
142
143 chain.handle_read(packet(Packet::Rtcp(vec![]))).unwrap();
144 assert!(chain.poll_read().is_none());
145 }
146
147 #[test]
148 fn inbound_rtp_passes_through() {
149 let mut chain = Registry::new().build();
150
151 chain
152 .handle_read(packet(Packet::Rtp(rtp::Packet::default())))
153 .unwrap();
154 assert!(chain.poll_read().is_some());
155 }
156
157 #[test]
159 fn outbound_rtcp_is_not_affected() {
160 let mut chain = Registry::new().build();
161
162 chain.handle_write(packet(Packet::Rtcp(vec![]))).unwrap();
163 assert!(chain.poll_write().is_some());
164 }
165
166 #[test]
169 fn stages_before_it_still_see_inbound_rtcp() {
170 #[derive(Default)]
171 struct Counter {
172 seen: std::sync::Arc<std::sync::atomic::AtomicUsize>,
173 read_queue: VecDeque<TaggedPacket>,
174 write_queue: VecDeque<TaggedPacket>,
175 }
176 impl Protocol<TaggedPacket, TaggedPacket, ()> for Counter {
177 type Rout = TaggedPacket;
178 type Wout = TaggedPacket;
179 type Eout = ();
180 type Error = Error;
181 type Time = Instant;
182
183 fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
184 if matches!(msg.message.packet, Packet::Rtcp(_)) {
185 self.seen.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
186 }
187 self.read_queue.push_back(msg);
188 Ok(())
189 }
190
191 fn poll_read(&mut self) -> Option<Self::Rout> {
192 self.read_queue.pop_front()
193 }
194
195 fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
196 self.write_queue.push_back(msg);
197 Ok(())
198 }
199
200 fn poll_write(&mut self) -> Option<Self::Wout> {
201 self.write_queue.pop_front()
202 }
203
204 fn handle_timeout(&mut self, _now: Instant) -> Result<(), Self::Error> {
205 Ok(())
206 }
207
208 fn poll_timeout(&mut self) -> Option<Self::Time> {
209 None
210 }
211 }
212 impl Interceptor for Counter {
213 fn bind_local_stream(&mut self, _info: &StreamInfo) {}
214 fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
215 fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
216 fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
217 }
218 let counter = Counter::default();
219 let seen = counter.seen.clone();
220 let mut chain = Registry::new().with(Slot::NackGenerator, counter).build();
221
222 chain.handle_read(packet(Packet::Rtcp(vec![]))).unwrap();
223
224 assert_eq!(1, seen.load(std::sync::atomic::Ordering::Relaxed));
225 assert!(chain.poll_read().is_none(), "but it stops at the terminus");
226 }
227}
228
229#[cfg(test)]
230mod carrier_tests {
231 use super::*;
232 use crate::{Attribute, AttributedPacket, Registry};
233 use sansio::Protocol;
234 use shared::TransportContext;
235 use std::time::Instant;
236
237 fn annotated(attribute: Option<Attribute>) -> TaggedPacket {
238 let mut message = AttributedPacket::new(Packet::Rtcp(vec![Box::new(
239 rtcp::receiver_report::ReceiverReport::default(),
240 )]));
241 if let Some(attribute) = attribute {
242 message.add(attribute);
243 }
244 TaggedPacket {
245 now: Instant::now(),
246 transport: TransportContext::default(),
247 message,
248 }
249 }
250
251 #[test]
255 fn an_annotated_report_passes_on_as_an_empty_carrier() {
256 let mut chain = Registry::new().build();
257 chain
258 .handle_read(annotated(Some(Attribute::TargetBitrateChanged {
259 bits_per_second: 750_000.0,
260 })))
261 .unwrap();
262
263 let carrier = chain.poll_read().expect("the attributes must get through");
264 assert!(
265 matches!(&carrier.message.packet, Packet::Rtcp(packets) if packets.is_empty()),
266 "the payload must be stripped: the application did not ask for RTCP"
267 );
268 assert!(
269 carrier.message.has(&Attribute::TargetBitrateChanged {
270 bits_per_second: 0.0
271 }),
272 "but the attribute must survive"
273 );
274 }
275
276 #[test]
278 fn an_unannotated_report_still_stops_here() {
279 let mut chain = Registry::new().build();
280 chain.handle_read(annotated(None)).unwrap();
281 assert!(chain.poll_read().is_none());
282 }
283
284 #[test]
287 fn deliver_to_application_keeps_the_payload() {
288 let mut chain = Registry::new().build();
289 chain
290 .handle_read(annotated(Some(Attribute::DeliverToApplication)))
291 .unwrap();
292
293 let delivered = chain.poll_read().expect("forwarded");
294 assert!(
295 matches!(&delivered.message.packet, Packet::Rtcp(packets) if !packets.is_empty()),
296 "this packet was judged worth delivering, payload and all"
297 );
298 }
299}