rtc_interceptor/rfc8888/
sender.rs1use super::recorder::CcFeedbackRecorder;
4use crate::stream_info::StreamInfo;
5use crate::{Interceptor, Packet, TaggedPacket, interceptor};
6use rtcp::transport_feedbacks::cc_feedback_report::Ecn;
7use shared::TransportContext;
8use shared::error::Error;
9use shared::time::SystemInstant;
10use std::collections::HashSet;
11use std::collections::VecDeque;
12use std::marker::PhantomData;
13use std::time::{Duration, Instant};
14
15pub const DEFAULT_INTERVAL: Duration = Duration::from_millis(100);
17
18pub const DEFAULT_MAX_REPORT_SIZE: usize = 1200;
20
21pub struct Rfc8888Builder<P> {
34 interval: Duration,
35 max_report_size: usize,
36 sender_ssrc: u32,
37 _phantom: PhantomData<P>,
38}
39
40impl<P> Default for Rfc8888Builder<P> {
41 fn default() -> Self {
42 Self {
43 interval: DEFAULT_INTERVAL,
44 max_report_size: DEFAULT_MAX_REPORT_SIZE,
45 sender_ssrc: 0,
46 _phantom: PhantomData,
47 }
48 }
49}
50
51impl<P> Rfc8888Builder<P> {
52 pub fn new() -> Self {
54 Self::default()
55 }
56
57 pub fn with_interval(mut self, interval: Duration) -> Self {
62 self.interval = interval;
63 self
64 }
65
66 pub fn with_max_report_size(mut self, max_report_size: usize) -> Self {
71 self.max_report_size = max_report_size;
72 self
73 }
74
75 pub fn with_sender_ssrc(mut self, sender_ssrc: u32) -> Self {
77 self.sender_ssrc = sender_ssrc;
78 self
79 }
80
81 pub fn build(self) -> impl FnOnce(P) -> Rfc8888Interceptor<P> {
83 move |inner| {
84 Rfc8888Interceptor::new(inner, self.interval, self.max_report_size, self.sender_ssrc)
85 }
86 }
87}
88
89#[derive(Interceptor)]
102pub struct Rfc8888Interceptor<P> {
103 #[next]
104 inner: P,
105 interval: Duration,
106 max_report_size: usize,
107 sender_ssrc: u32,
108 recorder: CcFeedbackRecorder,
109 streams: HashSet<u32>,
111 next_timeout: Option<Instant>,
112 epoch: Option<SystemInstant>,
115 write_queue: VecDeque<TaggedPacket>,
116}
117
118impl<P> Rfc8888Interceptor<P> {
119 fn new(inner: P, interval: Duration, max_report_size: usize, sender_ssrc: u32) -> Self {
120 Self {
121 inner,
122 interval,
123 max_report_size,
124 sender_ssrc,
125 recorder: CcFeedbackRecorder::new(),
126 streams: HashSet::new(),
127 next_timeout: None,
128 epoch: None,
129 write_queue: VecDeque::new(),
130 }
131 }
132
133 fn report_timestamp(&mut self, now: Instant) -> u32 {
135 let epoch = self.epoch.get_or_insert_with(|| SystemInstant::now(now));
136 (epoch.ntp(now) >> 16) as u32
137 }
138
139 fn arm(&mut self, now: Instant) {
141 if self.next_timeout.is_none() && !self.streams.is_empty() && !self.interval.is_zero() {
142 self.next_timeout = Some(now + self.interval);
143 }
144 }
145}
146
147#[interceptor]
148impl<P: Interceptor> Rfc8888Interceptor<P> {
149 #[overrides]
150 fn bind_remote_stream(&mut self, info: &StreamInfo) {
151 self.streams.insert(info.ssrc);
152 self.inner.bind_remote_stream(info);
153 }
154
155 #[overrides]
156 fn unbind_remote_stream(&mut self, info: &StreamInfo) {
157 self.streams.remove(&info.ssrc);
158 self.recorder.remove_stream(info.ssrc);
159 if self.streams.is_empty() {
160 self.next_timeout = None;
161 }
162 self.inner.unbind_remote_stream(info);
163 }
164
165 #[overrides]
166 fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
167 if let Packet::Rtp(rtp_packet) = &msg.message
168 && self.streams.contains(&rtp_packet.header.ssrc)
169 {
170 self.recorder.add_packet(
174 msg.now,
175 rtp_packet.header.ssrc,
176 rtp_packet.header.sequence_number,
177 Ecn::NotEct,
178 );
179 self.arm(msg.now);
180 }
181 self.inner.handle_read(msg)
182 }
183
184 #[overrides]
185 fn handle_timeout(&mut self, now: Self::Time) -> Result<(), Self::Error> {
186 self.arm(now);
187
188 if let Some(next_timeout) = self.next_timeout
189 && now >= next_timeout
190 {
191 self.next_timeout = Some(now + self.interval);
192
193 if !self.recorder.is_empty() {
194 let report_timestamp = self.report_timestamp(now);
195 let report = self.recorder.build_report(
196 now,
197 self.sender_ssrc,
198 report_timestamp,
199 self.max_report_size,
200 );
201 if !report.report_blocks.is_empty() {
202 self.write_queue.push_back(TaggedPacket {
203 now,
204 transport: TransportContext::default(),
205 message: Packet::Rtcp(vec![Box::new(report)]),
206 });
207 }
208 }
209 }
210
211 self.inner.handle_timeout(now)
212 }
213
214 #[overrides]
215 fn poll_timeout(&mut self) -> Option<Self::Time> {
216 match (self.next_timeout, self.inner.poll_timeout()) {
217 (Some(mine), Some(theirs)) => Some(mine.min(theirs)),
218 (mine, theirs) => mine.or(theirs),
219 }
220 }
221
222 #[overrides]
223 fn poll_write(&mut self) -> Option<Self::Wout> {
224 if let Some(packet) = self.write_queue.pop_front() {
227 return Some(packet);
228 }
229 self.inner.poll_write()
230 }
231}