1 #![warn(rust_2018_idioms)] 2 #![allow(dead_code)] 3 4 use async_trait::async_trait; 5 use error::Result; 6 use std::collections::HashMap; 7 use std::future::Future; 8 use std::pin::Pin; 9 use std::sync::Arc; 10 11 use stream_info::StreamInfo; 12 13 pub mod chain; 14 mod error; 15 pub mod mock; 16 pub mod nack; 17 pub mod noop; 18 pub mod registry; 19 pub mod report; 20 pub mod stats; 21 pub mod stream_info; 22 pub mod stream_reader; 23 pub mod twcc; 24 25 pub use error::Error; 26 27 /// Attributes are a generic key/value store used by interceptors 28 pub type Attributes = HashMap<usize, usize>; 29 30 /// InterceptorBuilder provides an interface for constructing interceptors 31 pub trait InterceptorBuilder { build(&self, id: &str) -> Result<Arc<dyn Interceptor + Send + Sync>>32 fn build(&self, id: &str) -> Result<Arc<dyn Interceptor + Send + Sync>>; 33 } 34 35 /// Interceptor can be used to add functionality to you PeerConnections by modifying any incoming/outgoing rtp/rtcp 36 /// packets, or sending your own packets as needed. 37 #[async_trait] 38 pub trait Interceptor { 39 /// bind_rtcp_reader lets you modify any incoming RTCP packets. It is called once per sender/receiver, however this might 40 /// change in the future. The returned method will be called once per packet batch. bind_rtcp_reader( &self, reader: Arc<dyn RTCPReader + Send + Sync>, ) -> Arc<dyn RTCPReader + Send + Sync>41 async fn bind_rtcp_reader( 42 &self, 43 reader: Arc<dyn RTCPReader + Send + Sync>, 44 ) -> Arc<dyn RTCPReader + Send + Sync>; 45 46 /// bind_rtcp_writer lets you modify any outgoing RTCP packets. It is called once per PeerConnection. The returned method 47 /// will be called once per packet batch. bind_rtcp_writer( &self, writer: Arc<dyn RTCPWriter + Send + Sync>, ) -> Arc<dyn RTCPWriter + Send + Sync>48 async fn bind_rtcp_writer( 49 &self, 50 writer: Arc<dyn RTCPWriter + Send + Sync>, 51 ) -> Arc<dyn RTCPWriter + Send + Sync>; 52 53 /// bind_local_stream lets you modify any outgoing RTP packets. It is called once for per LocalStream. The returned method 54 /// will be called once per rtp packet. bind_local_stream( &self, info: &StreamInfo, writer: Arc<dyn RTPWriter + Send + Sync>, ) -> Arc<dyn RTPWriter + Send + Sync>55 async fn bind_local_stream( 56 &self, 57 info: &StreamInfo, 58 writer: Arc<dyn RTPWriter + Send + Sync>, 59 ) -> Arc<dyn RTPWriter + Send + Sync>; 60 61 /// unbind_local_stream is called when the Stream is removed. It can be used to clean up any data related to that track. unbind_local_stream(&self, info: &StreamInfo)62 async fn unbind_local_stream(&self, info: &StreamInfo); 63 64 /// bind_remote_stream lets you modify any incoming RTP packets. It is called once for per RemoteStream. The returned method 65 /// will be called once per rtp packet. bind_remote_stream( &self, info: &StreamInfo, reader: Arc<dyn RTPReader + Send + Sync>, ) -> Arc<dyn RTPReader + Send + Sync>66 async fn bind_remote_stream( 67 &self, 68 info: &StreamInfo, 69 reader: Arc<dyn RTPReader + Send + Sync>, 70 ) -> Arc<dyn RTPReader + Send + Sync>; 71 72 /// unbind_remote_stream is called when the Stream is removed. It can be used to clean up any data related to that track. unbind_remote_stream(&self, info: &StreamInfo)73 async fn unbind_remote_stream(&self, info: &StreamInfo); 74 close(&self) -> Result<()>75 async fn close(&self) -> Result<()>; 76 } 77 78 /// RTPWriter is used by Interceptor.bind_local_stream. 79 #[async_trait] 80 pub trait RTPWriter { 81 /// write a rtp packet write(&self, pkt: &rtp::packet::Packet, attributes: &Attributes) -> Result<usize>82 async fn write(&self, pkt: &rtp::packet::Packet, attributes: &Attributes) -> Result<usize>; 83 } 84 85 pub type RTPWriterBoxFn = Box< 86 dyn (Fn( 87 &rtp::packet::Packet, 88 &Attributes, 89 ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + Sync>>) 90 + Send 91 + Sync, 92 >; 93 pub struct RTPWriterFn(pub RTPWriterBoxFn); 94 95 #[async_trait] 96 impl RTPWriter for RTPWriterFn { 97 /// write a rtp packet write(&self, pkt: &rtp::packet::Packet, attributes: &Attributes) -> Result<usize>98 async fn write(&self, pkt: &rtp::packet::Packet, attributes: &Attributes) -> Result<usize> { 99 self.0(pkt, attributes).await 100 } 101 } 102 103 /// RTPReader is used by Interceptor.bind_remote_stream. 104 #[async_trait] 105 pub trait RTPReader { 106 /// read a rtp packet read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>107 async fn read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>; 108 } 109 110 pub type RTPReaderBoxFn = Box< 111 dyn (Fn( 112 &mut [u8], 113 &Attributes, 114 ) -> Pin<Box<dyn Future<Output = Result<(usize, Attributes)>> + Send + Sync>>) 115 + Send 116 + Sync, 117 >; 118 pub struct RTPReaderFn(pub RTPReaderBoxFn); 119 120 #[async_trait] 121 impl RTPReader for RTPReaderFn { 122 /// read a rtp packet read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>123 async fn read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)> { 124 self.0(buf, attributes).await 125 } 126 } 127 128 /// RTCPWriter is used by Interceptor.bind_rtcpwriter. 129 #[async_trait] 130 pub trait RTCPWriter { 131 /// write a batch of rtcp packets write( &self, pkts: &[Box<dyn rtcp::packet::Packet + Send + Sync>], attributes: &Attributes, ) -> Result<usize>132 async fn write( 133 &self, 134 pkts: &[Box<dyn rtcp::packet::Packet + Send + Sync>], 135 attributes: &Attributes, 136 ) -> Result<usize>; 137 } 138 139 pub type RTCPWriterBoxFn = Box< 140 dyn (Fn( 141 &[Box<dyn rtcp::packet::Packet + Send + Sync>], 142 &Attributes, 143 ) -> Pin<Box<dyn Future<Output = Result<usize>> + Send + Sync>>) 144 + Send 145 + Sync, 146 >; 147 148 pub struct RTCPWriterFn(pub RTCPWriterBoxFn); 149 150 #[async_trait] 151 impl RTCPWriter for RTCPWriterFn { 152 /// write a batch of rtcp packets write( &self, pkts: &[Box<dyn rtcp::packet::Packet + Send + Sync>], attributes: &Attributes, ) -> Result<usize>153 async fn write( 154 &self, 155 pkts: &[Box<dyn rtcp::packet::Packet + Send + Sync>], 156 attributes: &Attributes, 157 ) -> Result<usize> { 158 self.0(pkts, attributes).await 159 } 160 } 161 162 /// RTCPReader is used by Interceptor.bind_rtcpreader. 163 #[async_trait] 164 pub trait RTCPReader { 165 /// read a batch of rtcp packets read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>166 async fn read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>; 167 } 168 169 pub type RTCPReaderBoxFn = Box< 170 dyn (Fn( 171 &mut [u8], 172 &Attributes, 173 ) -> Pin<Box<dyn Future<Output = Result<(usize, Attributes)>> + Send + Sync>>) 174 + Send 175 + Sync, 176 >; 177 178 pub struct RTCPReaderFn(pub RTCPReaderBoxFn); 179 180 #[async_trait] 181 impl RTCPReader for RTCPReaderFn { 182 /// read a batch of rtcp packets read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)>183 async fn read(&self, buf: &mut [u8], attributes: &Attributes) -> Result<(usize, Attributes)> { 184 self.0(buf, attributes).await 185 } 186 } 187 188 /// Helper for the tests. 189 #[cfg(test)] 190 mod test { 191 use std::future::Future; 192 use std::time::Duration; 193 timeout_or_fail<T>(duration: Duration, future: T) -> T::Output where T: Future,194 pub async fn timeout_or_fail<T>(duration: Duration, future: T) -> T::Output 195 where 196 T: Future, 197 { 198 tokio::time::timeout(duration, future) 199 .await 200 .expect("should not time out") 201 } 202 } 203