rtc_interceptor/twcc/
receiver.rs1use super::recorder::Recorder;
4use super::stream_supports_twcc;
5use crate::Interceptor;
6use crate::stream_info::StreamInfo;
7use crate::{AttributedPacket, Packet, TaggedPacket};
8use sansio::Protocol;
9use shared::TransportContext;
10use shared::error::Error;
11use shared::marshal::Unmarshal;
12use std::collections::{HashMap, VecDeque};
13use std::time::{Duration, Instant};
14
15const DEFAULT_INTERVAL: Duration = Duration::from_millis(100);
17
18pub struct TwccReceiverBuilder {
33 interval: Duration,
35}
36
37impl Default for TwccReceiverBuilder {
38 fn default() -> Self {
39 Self {
40 interval: DEFAULT_INTERVAL,
41 }
42 }
43}
44
45impl TwccReceiverBuilder {
46 pub fn new() -> Self {
48 Self::default()
49 }
50
51 pub fn with_interval(mut self, interval: Duration) -> Self {
53 self.interval = interval;
54 self
55 }
56
57 pub fn build(self) -> TwccReceiverInterceptor {
59 TwccReceiverInterceptor::new(self.interval)
60 }
61}
62
63struct RemoteStream {
65 hdr_ext_id: u8,
67}
68
69pub struct TwccReceiverInterceptor {
74 interval: Duration,
76
77 start_time: Option<Instant>,
79
80 recorder: Option<Recorder>,
82
83 streams: HashMap<u32, RemoteStream>,
85
86 write_queue: VecDeque<TaggedPacket>,
88
89 next_timeout: Option<Instant>,
91 read_queue: VecDeque<TaggedPacket>,
93}
94
95impl TwccReceiverInterceptor {
96 fn new(interval: Duration) -> Self {
97 Self {
98 read_queue: VecDeque::new(),
99 interval,
100 start_time: None,
101 recorder: None,
102 streams: HashMap::new(),
103 write_queue: VecDeque::new(),
104 next_timeout: None,
105 }
106 }
107
108 fn generate_feedback(&mut self, now: Instant) {
109 let Some(recorder) = self.recorder.as_mut() else {
110 return;
111 };
112
113 let packets = recorder.build_feedback_packet();
114 for pkt in packets {
115 self.write_queue.push_back(TaggedPacket {
116 now,
117 transport: TransportContext::default(),
118 message: AttributedPacket::new(Packet::Rtcp(vec![pkt])),
119 });
120 }
121 }
122}
123
124impl Protocol<TaggedPacket, TaggedPacket, ()> for TwccReceiverInterceptor {
125 type Rout = TaggedPacket;
126 type Wout = TaggedPacket;
127 type Eout = ();
128 type Error = Error;
129 type Time = Instant;
130
131 fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
132 if let Packet::Rtp(ref rtp_packet) = msg.message.packet
134 && let Some(stream) = self.streams.get(&rtp_packet.header.ssrc)
135 {
136 if self.recorder.is_none() {
138 self.recorder = Some(Recorder::new(rand::random()));
140 self.start_time = Some(msg.now);
141 self.next_timeout = Some(msg.now + self.interval);
142 }
143
144 if let Some(ext_data) = rtp_packet.header.get_extension(stream.hdr_ext_id)
146 && let Ok(tcc) =
147 rtp::extension::transport_cc_extension::TransportCcExtension::unmarshal(
148 &mut ext_data.as_ref(),
149 )
150 {
151 let arrival_time = self
153 .start_time
154 .map(|start| msg.now.duration_since(start).as_micros() as i64)
155 .unwrap_or(0);
156
157 if let Some(recorder) = self.recorder.as_mut() {
158 recorder.record(rtp_packet.header.ssrc, tcc.transport_sequence, arrival_time);
159 }
160 }
161 }
162
163 self.read_queue.push_back(msg);
164
165 Ok(())
166 }
167
168 fn poll_read(&mut self) -> Option<Self::Rout> {
169 self.read_queue.pop_front()
170 }
171
172 fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
173 self.write_queue.push_back(msg);
174 Ok(())
175 }
176
177 fn poll_write(&mut self) -> Option<TaggedPacket> {
178 if let Some(pkt) = self.write_queue.pop_front() {
180 return Some(pkt);
181 }
182 None
183 }
184
185 fn handle_timeout(&mut self, now: Instant) -> Result<(), Error> {
186 if let Some(timeout) = self.next_timeout
188 && now >= timeout
189 {
190 self.generate_feedback(now);
191 self.next_timeout = Some(now + self.interval);
192 }
193 Ok(())
194 }
195
196 fn poll_timeout(&mut self) -> Option<Instant> {
197 self.next_timeout
198 }
199}
200
201impl Interceptor for TwccReceiverInterceptor {
202 fn bind_remote_stream(&mut self, info: &StreamInfo) {
203 if let Some(hdr_ext_id) = stream_supports_twcc(info) {
204 if hdr_ext_id != 0 {
206 self.streams.insert(info.ssrc, RemoteStream { hdr_ext_id });
207 }
208 }
209 }
210
211 fn unbind_remote_stream(&mut self, info: &StreamInfo) {
212 self.streams.remove(&info.ssrc);
213 }
214
215 fn bind_local_stream(&mut self, _info: &StreamInfo) {}
216
217 fn unbind_local_stream(&mut self, _info: &StreamInfo) {}
218}