rtc_interceptor/intervalpli/
generator.rs1use super::stream_supports_pli;
4use crate::stream_info::StreamInfo;
5use crate::{Interceptor, Packet, TaggedPacket, interceptor};
6use shared::TransportContext;
7use shared::error::Error;
8use std::collections::{BTreeSet, VecDeque};
9use std::marker::PhantomData;
10use std::time::{Duration, Instant};
11
12pub const DEFAULT_INTERVAL: Duration = Duration::from_secs(3);
14
15pub struct IntervalPliBuilder<P> {
28 interval: Duration,
29 _phantom: PhantomData<P>,
30}
31
32impl<P> Default for IntervalPliBuilder<P> {
33 fn default() -> Self {
34 Self {
35 interval: DEFAULT_INTERVAL,
36 _phantom: PhantomData,
37 }
38 }
39}
40
41impl<P> IntervalPliBuilder<P> {
42 pub fn new() -> Self {
44 Self::default()
45 }
46
47 pub fn with_interval(mut self, interval: Duration) -> Self {
53 self.interval = interval;
54 self
55 }
56
57 pub fn build(self) -> impl FnOnce(P) -> IntervalPliInterceptor<P> {
59 move |inner| IntervalPliInterceptor::new(inner, self.interval)
60 }
61}
62
63#[derive(Interceptor)]
68pub struct IntervalPliInterceptor<P> {
69 #[next]
70 inner: P,
71 interval: Duration,
72 streams: BTreeSet<u32>,
74 pending_immediate: BTreeSet<u32>,
79 next_timeout: Option<Instant>,
80 write_queue: VecDeque<TaggedPacket>,
81}
82
83impl<P> IntervalPliInterceptor<P> {
84 fn new(inner: P, interval: Duration) -> Self {
85 Self {
86 inner,
87 interval,
88 streams: BTreeSet::new(),
89 pending_immediate: BTreeSet::new(),
90 next_timeout: None,
91 write_queue: VecDeque::new(),
92 }
93 }
94
95 pub fn force_pli(&mut self, now: Instant) {
105 let ssrcs: Vec<u32> = self.streams.iter().copied().collect();
106 self.queue_plis(now, &ssrcs);
107 }
108
109 pub fn force_pli_for(&mut self, now: Instant, ssrcs: &[u32]) {
114 let bound: Vec<u32> = ssrcs
115 .iter()
116 .copied()
117 .filter(|ssrc| self.streams.contains(ssrc))
118 .collect();
119 self.queue_plis(now, &bound);
120 }
121
122 pub fn bound_streams(&self) -> impl Iterator<Item = u32> + '_ {
124 self.streams.iter().copied()
125 }
126
127 fn queue_plis(&mut self, now: Instant, ssrcs: &[u32]) {
132 if ssrcs.is_empty() {
133 return;
134 }
135
136 let plis: Vec<Box<dyn rtcp::Packet>> = ssrcs
137 .iter()
138 .map(|&ssrc| {
139 Box::new(
140 rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication {
141 sender_ssrc: 0,
142 media_ssrc: ssrc,
143 },
144 ) as Box<dyn rtcp::Packet>
145 })
146 .collect();
147
148 self.write_queue.push_back(TaggedPacket {
149 now,
150 transport: TransportContext::default(),
151 message: Packet::Rtcp(plis),
152 });
153 }
154
155 fn observe(&mut self, now: Instant) {
158 if !self.pending_immediate.is_empty() {
159 let ssrcs: Vec<u32> = self.pending_immediate.iter().copied().collect();
160 self.pending_immediate.clear();
161 self.queue_plis(now, &ssrcs);
162 }
163
164 if self.next_timeout.is_none() && self.is_periodic() && !self.streams.is_empty() {
165 self.next_timeout = Some(now + self.interval);
166 }
167 }
168
169 fn is_periodic(&self) -> bool {
170 !self.interval.is_zero()
171 }
172}
173
174#[interceptor]
175impl<P: Interceptor> IntervalPliInterceptor<P> {
176 #[overrides]
177 fn bind_remote_stream(&mut self, info: &StreamInfo) {
178 if stream_supports_pli(info) {
179 self.streams.insert(info.ssrc);
180 self.pending_immediate.insert(info.ssrc);
181 }
182 self.inner.bind_remote_stream(info);
183 }
184
185 #[overrides]
186 fn unbind_remote_stream(&mut self, info: &StreamInfo) {
187 self.streams.remove(&info.ssrc);
188 self.pending_immediate.remove(&info.ssrc);
189 if self.streams.is_empty() {
190 self.next_timeout = None;
192 }
193 self.inner.unbind_remote_stream(info);
194 }
195
196 #[overrides]
197 fn handle_read(&mut self, msg: TaggedPacket) -> Result<(), Self::Error> {
198 self.observe(msg.now);
199 self.inner.handle_read(msg)
200 }
201
202 #[overrides]
203 fn handle_timeout(&mut self, now: Self::Time) -> Result<(), Self::Error> {
204 self.observe(now);
205
206 if let Some(next_timeout) = self.next_timeout
207 && now >= next_timeout
208 {
209 self.next_timeout = Some(now + self.interval);
210 let ssrcs: Vec<u32> = self.streams.iter().copied().collect();
211 self.queue_plis(now, &ssrcs);
212 }
213
214 self.inner.handle_timeout(now)
215 }
216
217 #[overrides]
218 fn poll_timeout(&mut self) -> Option<Self::Time> {
219 match (self.next_timeout, self.inner.poll_timeout()) {
220 (Some(mine), Some(theirs)) => Some(mine.min(theirs)),
221 (mine, theirs) => mine.or(theirs),
222 }
223 }
224
225 #[overrides]
226 fn poll_write(&mut self) -> Option<Self::Wout> {
227 if let Some(packet) = self.write_queue.pop_front() {
230 return Some(packet);
231 }
232 self.inner.poll_write()
233 }
234}