rtc_interceptor/cc/
interceptor.rs1use super::estimator::BandwidthEstimator;
4use crate::Interceptor;
5use crate::rtpfb::convert::{convert_ccfb, convert_twcc};
6use crate::rtpfb::history::History;
7use crate::stream_info::StreamInfo;
8use crate::twcc::stream_supports_twcc;
9use crate::{Attribute, Packet, TaggedPacket};
10use sansio::Protocol;
11use shared::error::Error;
12use shared::marshal::{MarshalSize, Unmarshal};
13use std::collections::{HashMap, VecDeque};
14use std::time::{Duration, Instant};
15
16pub const DEFAULT_PRUNE_HORIZON: Duration = Duration::from_secs(2);
23
24struct LocalStream {
26 hdr_ext_id: u8,
27}
28
29pub struct CongestionControlBuilder<E: BandwidthEstimator> {
42 estimator: E,
43 prune_horizon: Duration,
44}
45
46impl<E: BandwidthEstimator> CongestionControlBuilder<E> {
47 pub fn new(estimator: E) -> Self {
49 Self {
50 estimator,
51 prune_horizon: DEFAULT_PRUNE_HORIZON,
52 }
53 }
54
55 pub fn with_prune_horizon(mut self, prune_horizon: Duration) -> Self {
57 self.prune_horizon = prune_horizon;
58 self
59 }
60
61 pub fn build(self) -> CongestionControlInterceptor<E> {
63 CongestionControlInterceptor {
64 last_target: self.estimator.target_bitrate(),
65 estimator: self.estimator,
66 prune_horizon: self.prune_horizon,
67 history: History::new(),
68 streams: HashMap::new(),
69 read_queue: VecDeque::new(),
70 write_queue: VecDeque::new(),
71 }
72 }
73}
74
75pub struct CongestionControlInterceptor<E: BandwidthEstimator> {
100 estimator: E,
101 history: History,
102 streams: HashMap<u32, LocalStream>,
103 prune_horizon: Duration,
104 last_target: f64,
106 read_queue: VecDeque<TaggedPacket>,
107 write_queue: VecDeque<TaggedPacket>,
108}
109
110impl<E: BandwidthEstimator> CongestionControlInterceptor<E> {
111 pub fn estimator(&self) -> &E {
113 &self.estimator
114 }
115
116 pub fn outstanding(&self) -> usize {
118 self.history.len()
119 }
120
121 fn twcc_sequence_number(&self, rtp_packet: &rtp::Packet) -> Option<u16> {
127 let stream = self.streams.get(&rtp_packet.header.ssrc)?;
128 let mut extension = rtp_packet.header.get_extension(stream.hdr_ext_id)?;
129 rtp::extension::transport_cc_extension::TransportCcExtension::unmarshal(&mut extension)
130 .ok()
131 .map(|extension| extension.transport_sequence)
132 }
133
134 #[allow(clippy::borrowed_box)]
136 fn ingest(&mut self, now: Instant, rtcp_packet: &Box<dyn rtcp::Packet>) -> bool {
137 let payload = rtcp_packet.as_any();
138
139 if let Some(feedback) = payload
140 .downcast_ref::<rtcp::transport_feedbacks::transport_layer_cc::TransportLayerCc>(
141 ) {
142 for acknowledgement in convert_twcc(feedback) {
143 self.history.on_twcc_feedback(now, acknowledgement);
144 }
145 return true;
146 }
147
148 if let Some(feedback) = payload
149 .downcast_ref::<rtcp::transport_feedbacks::cc_feedback_report::CcFeedbackReport>(
150 ) {
151 let (_report_delay, per_stream) = convert_ccfb(feedback);
152 for (ssrc, acknowledgements) in per_stream {
153 for acknowledgement in acknowledgements {
154 self.history.on_ccfb_feedback(now, ssrc, acknowledgement);
155 }
156 }
157 return true;
158 }
159
160 false
161 }
162}
163
164impl<E: BandwidthEstimator> Protocol<TaggedPacket, TaggedPacket, ()>
165 for CongestionControlInterceptor<E>
166{
167 type Rout = TaggedPacket;
168 type Wout = TaggedPacket;
169 type Eout = ();
170 type Error = Error;
171 type Time = Instant;
172
173 fn handle_read(&mut self, mut msg: TaggedPacket) -> Result<(), Self::Error> {
174 let mut reported = false;
175 if let Packet::Rtcp(ref rtcp_packets) = msg.message.packet {
176 let feedback: Vec<_> = rtcp_packets.to_vec();
178 for rtcp_packet in &feedback {
179 reported |= self.ingest(msg.now, rtcp_packet);
180 }
181 }
182
183 if reported {
184 let reports = self.history.take_reports();
185 self.estimator.on_reports(msg.now, &reports);
186
187 let target = self.estimator.target_bitrate();
188 if target != self.last_target {
189 self.last_target = target;
190 msg.message.add(Attribute::TargetBitrateChanged {
193 bits_per_second: target,
194 });
195 }
196 }
197
198 self.read_queue.push_back(msg);
199 Ok(())
200 }
201
202 fn poll_read(&mut self) -> Option<Self::Rout> {
203 self.read_queue.pop_front()
204 }
205
206 fn handle_write(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
207 if let Packet::Rtp(ref rtp_packet) = msg.message.packet {
208 let twcc_sequence_number = self.twcc_sequence_number(rtp_packet);
209 if self.streams.contains_key(&rtp_packet.header.ssrc) {
212 self.history.add_outgoing(
213 rtp_packet.header.ssrc,
214 rtp_packet.header.sequence_number,
215 twcc_sequence_number.is_some(),
216 twcc_sequence_number.unwrap_or_default(),
217 rtp_packet.marshal_size(),
218 msg.now,
221 );
222 }
223 }
224
225 self.write_queue.push_back(msg);
226 Ok(())
227 }
228
229 fn poll_write(&mut self) -> Option<Self::Wout> {
230 self.write_queue.pop_front()
231 }
232
233 fn handle_timeout(&mut self, now: Instant) -> Result<(), Self::Error> {
234 self.history
235 .prune_before(now.checked_sub(self.prune_horizon).unwrap_or(now));
236 self.estimator.handle_timeout(now);
237 Ok(())
238 }
239
240 fn poll_timeout(&mut self) -> Option<Self::Time> {
245 self.estimator.poll_timeout()
246 }
247}
248
249impl<E: BandwidthEstimator> Interceptor for CongestionControlInterceptor<E> {
250 fn bind_local_stream(&mut self, info: &StreamInfo) {
251 let hdr_ext_id = stream_supports_twcc(info).unwrap_or_default();
254 self.streams.insert(info.ssrc, LocalStream { hdr_ext_id });
255 }
256
257 fn unbind_local_stream(&mut self, info: &StreamInfo) {
258 self.streams.remove(&info.ssrc);
259 }
260
261 fn bind_remote_stream(&mut self, _info: &StreamInfo) {}
262 fn unbind_remote_stream(&mut self, _info: &StreamInfo) {}
263}