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