rtc/rtp_transceiver/rtp_receiver/mod.rs
1//! RTP Receiver implementation following the W3C WebRTC specification.
2//!
3//! This module provides the [`RTCRtpReceiver`] which represents an RTP receiver
4//! as defined in the [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#rtcrtpreceiver-interface).
5//!
6//! # Overview
7//!
8//! An RTP receiver manages the reception of media from a remote peer, providing:
9//! - Access to the received media track
10//! - RTP capabilities and receive parameters
11//! - Contributing source (CSRC) and synchronization source (SSRC) information
12//! - Statistics about received media
13//!
14//! # Examples
15//!
16//! ## Accessing the received track
17//!
18//! ```no_run
19//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
20//! # use rtc::media_stream::MediaStreamTrackId;
21//! # use rtc::rtp_transceiver::RTCRtpReceiverId;
22//! # fn example(
23//! # receiver_id: RTCRtpReceiverId,
24//! # track_id: MediaStreamTrackId
25//! # ) -> Result<(), Box<dyn std::error::Error>> {
26//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
27//!
28//! // Get the receiver and access its track
29//! if let Some(receiver) = peer_connection.rtp_receiver(receiver_id) {
30//! let track = receiver.track();
31//! println!("Track ID: {}", track.track_id());
32//! println!("Track kind: {:?}", track.kind());
33//! println!("Track enabled: {}", track.enabled());
34//! }
35//! # Ok(())
36//! # }
37//! ```
38//!
39//! ## Getting receive parameters
40//!
41//! ```no_run
42//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
43//! # use rtc::rtp_transceiver::RTCRtpReceiverId;
44//! # fn example(receiver_id: RTCRtpReceiverId) -> Result<(), Box<dyn std::error::Error>> {
45//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
46//!
47//! if let Some(mut receiver) = peer_connection.rtp_receiver(receiver_id) {
48//! // Get current receive parameters
49//! let params = receiver.get_parameters();
50//!
51//! println!("Codecs: {:?}", params.rtp_parameters.codecs);
52//! println!("Header extensions: {:?}", params.rtp_parameters.header_extensions);
53//! println!("RTCP CNAME: {}", params.rtp_parameters.rtcp.cname);
54//! }
55//! # Ok(())
56//! # }
57//! ```
58//!
59//! ## Checking receiver capabilities
60//!
61//! ```no_run
62//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
63//! # use rtc::rtp_transceiver::rtp_sender::RtpCodecKind;
64//! # use rtc::rtp_transceiver::RTCRtpReceiverId;
65//! # fn example(receiver_id: RTCRtpReceiverId) -> Result<(), Box<dyn std::error::Error>> {
66//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
67//!
68//! if let Some(receiver) = peer_connection.rtp_receiver(receiver_id) {
69//! // Check video capabilities
70//! if let Some(capabilities) = receiver.get_capabilities(RtpCodecKind::Video) {
71//! println!("Supported video codecs:");
72//! for codec in capabilities.codecs {
73//! println!(" - {} @ {} Hz", codec.mime_type, codec.clock_rate);
74//! }
75//!
76//! println!("Supported header extensions:");
77//! for ext in capabilities.header_extensions {
78//! println!(" - {}", ext.uri);
79//! }
80//! }
81//! }
82//! # Ok(())
83//! # }
84//! ```
85//!
86//! ## Getting contributing sources
87//!
88//! ```no_run
89//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
90//! # use rtc::rtp_transceiver::RTCRtpReceiverId;
91//! # fn example(receiver_id: RTCRtpReceiverId) -> Result<(), Box<dyn std::error::Error>> {
92//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
93//!
94//! if let Some(mut receiver) = peer_connection.rtp_receiver(receiver_id) {
95//! // Get CSRC information for mixed audio
96//! for csrc in receiver.get_contributing_sources() {
97//! println!("CSRC: {}, timestamp: {:?}", csrc.source, csrc.timestamp);
98//! println!(" Audio level: {}", csrc.audio_level);
99//! println!(" RTP timestamp: {}", csrc.rtp_timestamp);
100//! }
101//! }
102//! # Ok(())
103//! # }
104//! ```
105//!
106//! ## Getting synchronization sources
107//!
108//! ```no_run
109//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
110//! # use rtc::rtp_transceiver::RTCRtpReceiverId;
111//! # fn example(receiver_id: RTCRtpReceiverId) -> Result<(), Box<dyn std::error::Error>> {
112//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
113//!
114//! if let Some(mut receiver) = peer_connection.rtp_receiver(receiver_id) {
115//! // Get SSRC information
116//! for ssrc in receiver.get_synchronization_sources() {
117//! println!("SSRC: {}, timestamp: {:?}", ssrc.source, ssrc.timestamp);
118//! println!(" RTP timestamp: {}", ssrc.rtp_timestamp);
119//! }
120//! }
121//! # Ok(())
122//! # }
123//! ```
124//!
125//! ## Handling incoming receivers
126//!
127//! ```no_run
128//! # use rtc::peer_connection::RTCPeerConnectionBuilder;
129//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
130//! let mut peer_connection = RTCPeerConnectionBuilder::new().build()?;
131//!
132//! // After remote description is set, collect receiver IDs first
133//! let receiver_ids: Vec<_> = peer_connection.get_receivers().collect();
134//!
135//! // Then iterate and process each receiver
136//! for receiver_id in receiver_ids {
137//! if let Some(receiver) = peer_connection.rtp_receiver(receiver_id) {
138//! // Access the remote track (track_id would come from signaling)
139//! // Process the incoming media as needed
140//! }
141//! }
142//! # Ok(())
143//! # }
144//! ```
145//!
146//! # Specifications
147//!
148//! * [W3C RTCRtpReceiver](https://www.w3.org/TR/webrtc/#rtcrtpreceiver-interface)
149//! * [MDN RTCRtpReceiver](https://developer.mozilla.org/en-US/docs/Web/API/RTCRtpReceiver)
150
151//TODO: #[cfg(test)]
152//mod rtp_receiver_test;
153
154pub(crate) mod internal;
155pub(crate) mod rtp_contributing_source;
156
157use crate::media_stream::track::MediaStreamTrack;
158use crate::peer_connection::RTCPeerConnection;
159use crate::peer_connection::message::RTCMessage;
160use crate::rtp_transceiver::RTCRtpReceiverId;
161use crate::rtp_transceiver::rtp_sender::rtp_capabilities::RTCRtpCapabilities;
162use crate::rtp_transceiver::rtp_sender::rtp_codec::RtpCodecKind;
163use crate::rtp_transceiver::rtp_sender::rtp_receiver_parameters::RTCRtpReceiveParameters;
164use interceptor::{Interceptor, NoopInterceptor};
165use sansio::Protocol;
166use shared::error::Result;
167
168pub use rtp_contributing_source::{RTCRtpContributingSource, RTCRtpSynchronizationSource};
169
170/// Represents an RTP receiver for a media stream track.
171///
172/// The `RTCRtpReceiver` interface allows an application to inspect the receipt of a
173/// [`MediaStreamTrack`] as defined in the [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#rtcrtpreceiver-interface).
174///
175/// # Lifetime
176///
177/// This struct borrows the [`RTCPeerConnection`] mutably, ensuring exclusive access
178/// during RTP receiver operations.
179pub struct RTCRtpReceiver<'a, I = NoopInterceptor>
180where
181 I: Interceptor,
182{
183 pub(crate) id: RTCRtpReceiverId,
184 pub(crate) peer_connection: &'a mut RTCPeerConnection<I>,
185}
186
187impl<I> RTCRtpReceiver<'_, I>
188where
189 I: Interceptor,
190{
191 /// Returns the track associated with this receiver.
192 ///
193 /// The [`track`](RTCRtpReceiver::track) method returns the [`MediaStreamTrack`] that is
194 /// associated with this receiver as specified in the [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#dom-rtcrtpreceiver-track).
195 ///
196 /// # Returns
197 ///
198 /// Returns a reference to the [`MediaStreamTrack`] associated with this receiver.
199 pub fn track(&self) -> &MediaStreamTrack {
200 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
201 // the direction won't be changed too, so, unwrap() here is safe.
202 self.peer_connection.rtp_transceivers[self.id.0]
203 .receiver
204 .as_ref()
205 .unwrap()
206 .track()
207 }
208
209 /// Returns the RTP capabilities for the specified codec kind.
210 ///
211 /// The static [`get_capabilities`](RTCRtpReceiver::get_capabilities) method returns the most
212 /// optimistic view of the capabilities of the system for receiving media of the given kind
213 /// as defined in the [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#dom-rtcrtpreceiver-getcapabilities).
214 ///
215 /// # Parameters
216 ///
217 /// * `kind` - The codec kind (audio or video)
218 ///
219 /// # Returns
220 ///
221 /// Returns the RTP capabilities supported by this receiver for the specified codec kind.
222 pub fn get_capabilities(&self, kind: RtpCodecKind) -> Option<RTCRtpCapabilities> {
223 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
224 // the direction won't be changed too, so, unwrap() here is safe.
225 self.peer_connection.rtp_transceivers[self.id.0]
226 .receiver
227 .as_ref()
228 .unwrap()
229 .get_capabilities(kind, &self.peer_connection.media_engine)
230 }
231
232 /// Returns the RTP receive parameters for this receiver.
233 ///
234 /// The [`get_parameters`](RTCRtpReceiver::get_parameters) method returns the current parameters
235 /// for how the receiver's track is decoded as defined in the
236 /// [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#dom-rtcrtpreceiver-getparameters).
237 ///
238 /// # Returns
239 ///
240 /// Returns a reference to the RTP receive parameters.
241 pub fn get_parameters(&mut self) -> &RTCRtpReceiveParameters {
242 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
243 // the direction won't be changed too, so, unwrap() here is safe.
244 self.peer_connection.rtp_transceivers[self.id.0]
245 .receiver
246 .as_mut()
247 .unwrap()
248 .get_parameters(&self.peer_connection.media_engine)
249 }
250
251 /// Returns an iterator over the contributing sources for this receiver.
252 ///
253 /// The [`get_contributing_sources`](RTCRtpReceiver::get_contributing_sources) method returns
254 /// information about the contributing sources (CSRCs) for the most recent RTP packets
255 /// received by this receiver as defined in the
256 /// [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#dom-rtcrtpreceiver-getcontributingsources).
257 ///
258 /// Contributing sources represent mixers or other entities that have contributed to the
259 /// RTP stream.
260 ///
261 /// # Returns
262 ///
263 /// Returns an iterator over [`RTCRtpContributingSource`] objects.
264 pub fn get_contributing_sources(&self) -> impl Iterator<Item = &RTCRtpContributingSource> {
265 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
266 // the direction won't be changed too, so, unwrap() here is safe.
267 self.peer_connection.rtp_transceivers[self.id.0]
268 .receiver
269 .as_ref()
270 .unwrap()
271 .get_contributing_sources()
272 }
273
274 /// Returns an iterator over the synchronization sources for this receiver.
275 ///
276 /// The [`get_synchronization_sources`](RTCRtpReceiver::get_synchronization_sources) method
277 /// returns information about the synchronization sources (SSRCs) for the most recent RTP
278 /// packets received by this receiver as defined in the
279 /// [W3C WebRTC specification](https://www.w3.org/TR/webrtc/#dom-rtcrtpreceiver-getsynchronizationsources).
280 ///
281 /// Synchronization sources represent the original sources of the RTP packets.
282 ///
283 /// # Returns
284 ///
285 /// Returns an iterator over [`RTCRtpSynchronizationSource`] objects.
286 pub fn get_synchronization_sources(
287 &self,
288 ) -> impl Iterator<Item = &RTCRtpSynchronizationSource> {
289 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
290 // the direction won't be changed too, so, unwrap() here is safe.
291 self.peer_connection.rtp_transceivers[self.id.0]
292 .receiver
293 .as_ref()
294 .unwrap()
295 .get_synchronization_sources()
296 }
297
298 /// Writes RTCP feedback packets for this receiver.
299 ///
300 /// This method allows sending receiver-side RTCP feedback such as:
301 /// - Receiver Reports (RR)
302 /// - Picture Loss Indication (PLI)
303 /// - Full Intra Request (FIR)
304 /// - Negative Acknowledgements (NACK)
305 ///
306 /// # Parameters
307 ///
308 /// * `packets` - A vector of RTCP packets to send
309 ///
310 /// # Returns
311 ///
312 /// Returns `Ok(())` if the packets were queued successfully.
313 ///
314 /// # Errors
315 ///
316 /// Returns an error if internal handle_write returns error
317 ///
318 /// # Example
319 ///
320 /// ```ignore
321 /// // Send a Picture Loss Indication to request a keyframe
322 /// use rtcp::picture_loss_indication::PictureLossIndication;
323 ///
324 /// let pli = PictureLossIndication {
325 /// sender_ssrc: 0,
326 /// media_ssrc: remote_ssrc,
327 /// };
328 /// receiver.write_rtcp(vec![Box::new(pli)])?;
329 /// ```
330 pub fn write_rtcp(&mut self, packets: Vec<Box<dyn rtcp::Packet>>) -> Result<()> {
331 // peer_connection is mutable borrow, its rtp_transceivers won't be resized and
332 // the direction won't be changed too, so, unwrap() here is safe.
333
334 //TODO: handle rtcp media ssrc, header extension, etc.
335 let receiver = self.peer_connection.rtp_transceivers[self.id.0]
336 .receiver
337 .as_mut()
338 .unwrap();
339
340 let track_id = receiver.track().track_id().to_string();
341 self.peer_connection
342 .handle_write(RTCMessage::RtcpPacket(track_id, packets))
343 }
344}