Skip to main content

rtc_interceptor/
noop.rs

1//! NoOp Interceptor - A pass-through terminal for interceptor chains.
2
3use crate::stream_info::StreamInfo;
4use crate::{Interceptor, Packet, TaggedPacket};
5use shared::error::Error;
6use std::collections::VecDeque;
7use std::time::Instant;
8
9/// A no-operation interceptor that simply queues messages for pass-through.
10///
11/// `NoopInterceptor` serves as the innermost layer of an interceptor chain.
12/// It accepts messages via `handle_read`/`handle_write`/etc and returns them
13/// unchanged via `poll_read`/`poll_write`/etc.
14///
15/// # Example
16///
17/// ```ignore
18/// use rtc_interceptor::NoopInterceptor;
19/// use sansio::Protocol;
20///
21/// let mut noop = NoopInterceptor::new();
22/// noop.handle_read(TaggedPacket::Rtp(...)).unwrap();
23/// assert!(noop.poll_read().is_some());
24/// ```
25pub struct NoopInterceptor {
26    read_queue: VecDeque<TaggedPacket>,
27    write_queue: VecDeque<TaggedPacket>,
28}
29
30impl NoopInterceptor {
31    /// Create a new NoopInterceptor.
32    pub fn new() -> Self {
33        Self {
34            read_queue: VecDeque::new(),
35            write_queue: VecDeque::new(),
36        }
37    }
38}
39
40impl Default for NoopInterceptor {
41    fn default() -> Self {
42        Self::new()
43    }
44}
45
46impl sansio::Protocol<TaggedPacket, TaggedPacket, ()> for NoopInterceptor {
47    type Rout = TaggedPacket;
48    type Wout = TaggedPacket;
49    type Eout = ();
50    type Error = Error;
51    type Time = Instant;
52
53    fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
54        if let Packet::Rtp(_) = &msg.message {
55            self.read_queue.push_back(msg);
56        }
57        // RTCP message read must end here. If any rtcp packet needs to be forwarded to PeerConnection,
58        // just add a new interceptor to forward it by using self.interceptor.poll_read()
59        Ok(())
60    }
61
62    fn poll_read(&mut self) -> Option<Self::Rout> {
63        self.read_queue.pop_front()
64    }
65
66    fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
67        self.write_queue.push_back(msg);
68        Ok(())
69    }
70
71    fn poll_write(&mut self) -> Option<Self::Wout> {
72        self.write_queue.pop_front()
73    }
74
75    fn handle_event(&mut self, _evt: ()) -> Result<(), Self::Error> {
76        Ok(())
77    }
78
79    fn poll_event(&mut self) -> Option<Self::Eout> {
80        None
81    }
82
83    fn handle_timeout(&mut self, _now: Self::Time) -> Result<(), Self::Error> {
84        Ok(())
85    }
86
87    fn poll_timeout(&mut self) -> Option<Self::Time> {
88        None
89    }
90
91    fn close(&mut self) -> Result<(), Self::Error> {
92        self.read_queue.clear();
93        self.write_queue.clear();
94        Ok(())
95    }
96}
97
98impl Interceptor for NoopInterceptor {
99    fn bind_local_stream(&mut self, _info: &StreamInfo) {}
100    fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
101    fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
102    fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108    use sansio::Protocol;
109
110    fn dummy_rtp_packet() -> TaggedPacket {
111        TaggedPacket {
112            now: Instant::now(),
113            transport: Default::default(),
114            message: crate::Packet::Rtp(rtp::Packet::default()),
115        }
116    }
117
118    fn dummy_rtcp_packet() -> TaggedPacket {
119        TaggedPacket {
120            now: Instant::now(),
121            transport: Default::default(),
122            message: crate::Packet::Rtcp(vec![Box::new(rtcp::raw_packet::RawPacket::default())]),
123        }
124    }
125
126    #[test]
127    fn test_noop_read_write() {
128        let mut noop = NoopInterceptor::new();
129
130        // Test read
131        let pkt1 = dummy_rtp_packet();
132        let pkt1_message = pkt1.message.clone();
133        let pkt2 = dummy_rtcp_packet();
134        noop.handle_read(pkt1).unwrap();
135        noop.handle_read(pkt2).unwrap();
136        assert_eq!(noop.poll_read().unwrap().message, pkt1_message);
137        assert!(noop.poll_read().is_none());
138
139        // Test write
140        let pkt3 = dummy_rtp_packet();
141        let pkt4 = dummy_rtp_packet();
142        let pkt3_message = pkt3.message.clone();
143        let pkt4_message = pkt4.message.clone();
144        noop.handle_write(pkt3).unwrap();
145        noop.handle_write(pkt4).unwrap();
146        assert_eq!(noop.poll_write().unwrap().message, pkt3_message);
147        assert_eq!(noop.poll_write().unwrap().message, pkt4_message);
148        assert!(noop.poll_write().is_none());
149    }
150
151    #[test]
152    fn test_noop_close_clears_queues() {
153        let mut noop = NoopInterceptor::new();
154
155        noop.handle_read(dummy_rtp_packet()).unwrap();
156        noop.handle_write(dummy_rtp_packet()).unwrap();
157
158        noop.close().unwrap();
159
160        assert!(noop.poll_read().is_none());
161        assert!(noop.poll_write().is_none());
162    }
163}