xref: /webrtc/interceptor/src/nack/responder/mod.rs (revision 6ac0fffd)
1 mod responder_stream;
2 #[cfg(test)]
3 mod responder_test;
4 
5 use crate::stream_info::StreamInfo;
6 use crate::{
7     Attributes, Interceptor, InterceptorBuilder, RTCPReader, RTCPWriter, RTPReader, RTPWriter,
8 };
9 use responder_stream::ResponderStream;
10 
11 use crate::error::Result;
12 use crate::nack::stream_support_nack;
13 
14 use async_trait::async_trait;
15 use rtcp::transport_feedbacks::transport_layer_nack::TransportLayerNack;
16 use std::collections::HashMap;
17 use std::future::Future;
18 use std::pin::Pin;
19 use std::sync::Arc;
20 use tokio::sync::Mutex;
21 
22 /// GeneratorBuilder can be used to configure Responder Interceptor
23 #[derive(Default)]
24 pub struct ResponderBuilder {
25     log2_size: Option<u8>,
26 }
27 
28 impl ResponderBuilder {
29     /// with_log2_size sets the size of the interceptor.
30     /// Size must be one of: 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768
31     pub fn with_log2_size(mut self, log2_size: u8) -> ResponderBuilder {
32         self.log2_size = Some(log2_size);
33         self
34     }
35 }
36 
37 impl InterceptorBuilder for ResponderBuilder {
38     fn build(&self, _id: &str) -> Result<Arc<dyn Interceptor + Send + Sync>> {
39         Ok(Arc::new(Responder {
40             internal: Arc::new(ResponderInternal {
41                 log2_size: if let Some(log2_size) = self.log2_size {
42                     log2_size
43                 } else {
44                     13 // 8192 = 1 << 13
45                 },
46                 streams: Arc::new(Mutex::new(HashMap::new())),
47             }),
48         }))
49     }
50 }
51 
52 pub struct ResponderInternal {
53     log2_size: u8,
54     streams: Arc<Mutex<HashMap<u32, Arc<ResponderStream>>>>,
55 }
56 
57 impl ResponderInternal {
58     async fn resend_packets(
59         streams: Arc<Mutex<HashMap<u32, Arc<ResponderStream>>>>,
60         nack: TransportLayerNack,
61     ) {
62         let stream = {
63             let m = streams.lock().await;
64             if let Some(stream) = m.get(&nack.media_ssrc) {
65                 stream.clone()
66             } else {
67                 return;
68             }
69         };
70 
71         for n in &nack.nacks {
72             let stream2 = Arc::clone(&stream);
73             n.range(Box::new(
74                 move |seq: u16| -> Pin<Box<dyn Future<Output = bool> + Send + 'static>> {
75                     let stream3 = Arc::clone(&stream2);
76                     Box::pin(async move {
77                         if let Some(p) = stream3.get(seq).await {
78                             let a = Attributes::new();
79                             if let Err(err) = stream3.next_rtp_writer.write(&p, &a).await {
80                                 log::warn!("failed resending nacked packet: {}", err);
81                             }
82                         }
83 
84                         true
85                     })
86                 },
87             ))
88             .await;
89         }
90     }
91 }
92 
93 pub struct ResponderRtcpReader {
94     parent_rtcp_reader: Arc<dyn RTCPReader + Send + Sync>,
95     internal: Arc<ResponderInternal>,
96 }
97 
98 #[async_trait]
99 impl RTCPReader for ResponderRtcpReader {
100     async fn read(&self, buf: &mut [u8], a: &Attributes) -> Result<(usize, Attributes)> {
101         let (n, attr) = { self.parent_rtcp_reader.read(buf, a).await? };
102 
103         let mut b = &buf[..n];
104         let pkts = rtcp::packet::unmarshal(&mut b)?;
105         for p in &pkts {
106             if let Some(nack) = p.as_any().downcast_ref::<TransportLayerNack>() {
107                 let nack = nack.clone();
108                 let streams = Arc::clone(&self.internal.streams);
109                 tokio::spawn(async move {
110                     ResponderInternal::resend_packets(streams, nack).await;
111                 });
112             }
113         }
114 
115         Ok((n, attr))
116     }
117 }
118 
119 /// Responder responds to nack feedback messages
120 pub struct Responder {
121     internal: Arc<ResponderInternal>,
122 }
123 
124 impl Responder {
125     /// builder returns a new ResponderBuilder.
126     pub fn builder() -> ResponderBuilder {
127         ResponderBuilder::default()
128     }
129 }
130 
131 #[async_trait]
132 impl Interceptor for Responder {
133     /// bind_rtcp_reader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might
134     /// change in the future. The returned method will be called once per packet batch.
135     async fn bind_rtcp_reader(
136         &self,
137         reader: Arc<dyn RTCPReader + Send + Sync>,
138     ) -> Arc<dyn RTCPReader + Send + Sync> {
139         Arc::new(ResponderRtcpReader {
140             internal: Arc::clone(&self.internal),
141             parent_rtcp_reader: reader,
142         }) as Arc<dyn RTCPReader + Send + Sync>
143     }
144 
145     /// bind_rtcp_writer lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method
146     /// will be called once per packet batch.
147     async fn bind_rtcp_writer(
148         &self,
149         writer: Arc<dyn RTCPWriter + Send + Sync>,
150     ) -> Arc<dyn RTCPWriter + Send + Sync> {
151         writer
152     }
153 
154     /// bind_local_stream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method
155     /// will be called once per rtp packet.
156     async fn bind_local_stream(
157         &self,
158         info: &StreamInfo,
159         writer: Arc<dyn RTPWriter + Send + Sync>,
160     ) -> Arc<dyn RTPWriter + Send + Sync> {
161         if !stream_support_nack(info) {
162             return writer;
163         }
164 
165         let stream = Arc::new(ResponderStream::new(self.internal.log2_size, writer));
166         {
167             let mut streams = self.internal.streams.lock().await;
168             streams.insert(info.ssrc, Arc::clone(&stream));
169         }
170 
171         stream
172     }
173 
174     /// unbind_local_stream is called when the Stream is removed. It can be used to clean up any data related to that track.
175     async fn unbind_local_stream(&self, info: &StreamInfo) {
176         let mut streams = self.internal.streams.lock().await;
177         streams.remove(&info.ssrc);
178     }
179 
180     /// bind_remote_stream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method
181     /// will be called once per rtp packet.
182     async fn bind_remote_stream(
183         &self,
184         _info: &StreamInfo,
185         reader: Arc<dyn RTPReader + Send + Sync>,
186     ) -> Arc<dyn RTPReader + Send + Sync> {
187         reader
188     }
189 
190     /// unbind_remote_stream is called when the Stream is removed. It can be used to clean up any data related to that track.
191     async fn unbind_remote_stream(&self, _info: &StreamInfo) {}
192 
193     /// close closes the Interceptor, cleaning up any data if necessary.
194     async fn close(&self) -> Result<()> {
195         Ok(())
196     }
197 }
198