rtc/
lib.rs

1//! # RTC - Sans-I/O WebRTC Implementation
2//!
3//! A Rust implementation of the [WebRTC specification](https://www.w3.org/TR/webrtc/) using a
4//! **sans-I/O architecture**. This crate provides full WebRTC functionality while giving you
5//! complete control over networking, threading, and async runtime integration.
6//!
7//! ## What is Sans-I/O?
8//!
9//! Sans-I/O (without I/O) is a design pattern that separates protocol logic from I/O operations.
10//! Instead of the library performing network reads and writes directly, **you** provide the
11//! network data and handle the output. This gives you:
12//!
13//! - **Runtime Independence**: Works with tokio, async-std, smol, or blocking I/O
14//! - **Full Control**: You control threading, scheduling, and I/O multiplexing
15//! - **Testability**: Protocol logic can be tested without real network I/O
16//! - **Flexibility**: Easy integration with existing networking code
17//!
18//! ## Quick Start
19//!
20//! ```no_run
21//! use rtc::peer_connection::RTCPeerConnection;
22//! use rtc::peer_connection::configuration::RTCConfigurationBuilder;
23//! use rtc::peer_connection::transport::RTCIceServer;
24//! use rtc::peer_connection::sdp::RTCSessionDescription;
25//! use rtc::peer_connection::transport::{CandidateConfig, CandidateHostConfig, RTCIceCandidate};
26//!
27//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
28//! // 1. Create a peer connection with ICE servers
29//! let config = RTCConfigurationBuilder::new()
30//!     .with_ice_servers(vec![RTCIceServer {
31//!         urls: vec!["stun:stun.l.google.com:19302".to_string()],
32//!         ..Default::default()
33//!     }])
34//!     .build();
35//!
36//! let mut pc = RTCPeerConnection::new(config)?;
37//!
38//! // 2. Create an offer
39//! let offer = pc.create_offer(None)?;
40//! pc.set_local_description(offer.clone())?;
41//!
42//! // Send offer to remote peer via your signaling channel
43//! // signaling.send(offer.sdp)?;
44//!
45//! // 3. Receive answer from remote peer
46//! // let answer_sdp = signaling.receive()?;
47//! # let answer_sdp = String::new();
48//! let answer = RTCSessionDescription::answer(answer_sdp)?;
49//! pc.set_remote_description(answer)?;
50//!
51//! // 4. Add local ICE candidate
52//! # use std::net::{IpAddr, Ipv4Addr};
53//! let candidate = CandidateHostConfig {
54//!     base_config: CandidateConfig {
55//!         network: "udp".to_owned(),
56//!         address: "192.168.1.100".to_string(),
57//!         port: 8080,
58//!         component: 1,
59//!         ..Default::default()
60//!     },
61//!     ..Default::default()
62//! }
63//! .new_candidate_host()?;
64//! let local_candidate_init = RTCIceCandidate::from(&candidate).to_json()?;
65//! pc.add_local_candidate(local_candidate_init)?;
66//!
67//! // 5. Event loop - see complete example below
68//! # Ok(())
69//! # }
70//! ```
71//!
72//! ## Complete Event Loop with All API Calls
73//!
74//! This example demonstrates the full sans-I/O event loop pattern with all key API methods:
75//!
76//! ```no_run
77//! use rtc::peer_connection::RTCPeerConnection;
78//! use rtc::peer_connection::configuration::{RTCConfigurationBuilder, media_engine::MediaEngine};
79//! use rtc::peer_connection::transport::RTCIceServer;
80//! use rtc::peer_connection::event::{RTCPeerConnectionEvent, RTCTrackEvent};
81//! use rtc::peer_connection::state::{RTCPeerConnectionState, RTCIceConnectionState};
82//! use rtc::peer_connection::message::RTCMessage;
83//! use rtc::shared::{TaggedBytesMut, TransportContext, TransportProtocol};
84//! use rtc::sansio::Protocol;
85//! use std::time::{Duration, Instant};
86//! use tokio::net::UdpSocket;
87//! use bytes::BytesMut;
88//!
89//! # #[tokio::main]
90//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
91//! // Configure media codecs
92//! let media_engine = MediaEngine::default();
93//!
94//! // Create peer connection configuration
95//! let config = RTCConfigurationBuilder::new()
96//!     .with_ice_servers(vec![RTCIceServer {
97//!         urls: vec!["stun:stun.l.google.com:19302".to_string()],
98//!         ..Default::default()
99//!     }])
100//!     .with_media_engine(media_engine)
101//!     .build();
102//!
103//! let mut pc = RTCPeerConnection::new(config)?;
104//!
105//! // Bind UDP socket for network I/O
106//! let socket = UdpSocket::bind("0.0.0.0:0").await?;
107//! let local_addr = socket.local_addr()?;
108//!
109//! let mut buf = vec![0u8; 2000];
110//! const DEFAULT_TIMEOUT: Duration = Duration::from_secs(86400);
111//!
112//! // Main event loop
113//! loop {
114//!     // 1. poll_write() - Get outgoing network packets
115//!     while let Some(msg) = pc.poll_write() {
116//!         socket.send_to(&msg.message, msg.transport.peer_addr).await?;
117//!     }
118//!
119//!     // 2. poll_event() - Process connection state changes and events
120//!     while let Some(event) = pc.poll_event() {
121//!         match event {
122//!             RTCPeerConnectionEvent::OnIceConnectionStateChangeEvent(state) => {
123//!                 println!("ICE Connection State: {state}");
124//!                 if state == RTCIceConnectionState::Failed {
125//!                     break;
126//!                 }
127//!             }
128//!             RTCPeerConnectionEvent::OnConnectionStateChangeEvent(state) => {
129//!                 println!("Connection State: {state}");
130//!                 if state == RTCPeerConnectionState::Failed {
131//!                     return Ok(());
132//!                 }
133//!             }
134//!             RTCPeerConnectionEvent::OnDataChannel(dc_event) => {
135//!                 println!("Data channel event: {:?}", dc_event);
136//!             }
137//!             RTCPeerConnectionEvent::OnTrack(track_event) => {
138//!                 match track_event {
139//!                     RTCTrackEvent::OnOpen(init) => {
140//!                         println!("Track opened: track_id={}, receiver_id={:?}",
141//!                             init.track_id, init.receiver_id);
142//!                     }
143//!                     RTCTrackEvent::OnClose(track_id) => {
144//!                         println!("Track closed: {track_id}");
145//!                     }
146//!                     _ => {}
147//!                 }
148//!             }
149//!             _ => {}
150//!         }
151//!     }
152//!
153//!     // 3. poll_read() - Get incoming application messages (RTP/RTCP/data)
154//!     while let Some(message) = pc.poll_read() {
155//!         match message {
156//!             RTCMessage::RtpPacket(track_id, rtp_packet) => {
157//!                 println!("Received RTP packet on track {track_id}");
158//!                 // Process RTP packet
159//!             }
160//!             RTCMessage::RtcpPacket(receiver_id, rtcp_packets) => {
161//!                 println!("Received RTCP packets on receiver {:?}", receiver_id);
162//!                 // Process RTCP packets
163//!             }
164//!             RTCMessage::DataChannelMessage(channel_id, message) => {
165//!                 println!("Received data channel message on channel {:?}", channel_id);
166//!                 // Process data channel message
167//!             }
168//!         }
169//!     }
170//!
171//!     // 4. poll_timeout() - Get next timer deadline
172//!     let timeout = pc.poll_timeout()
173//!         .unwrap_or(Instant::now() + DEFAULT_TIMEOUT);
174//!     let delay = timeout.saturating_duration_since(Instant::now());
175//!
176//!     // Handle immediate timeout
177//!     if delay.is_zero() {
178//!         // 6. handle_timeout() - Notify about timer expiration
179//!         pc.handle_timeout(Instant::now())?;
180//!         continue;
181//!     }
182//!
183//!     // Wait for events using tokio::select!
184//!     let timer = tokio::time::sleep(delay);
185//!     tokio::pin!(timer);
186//!
187//!     tokio::select! {
188//!         biased;
189//!
190//!         // Timer expired
191//!         _ = timer => {
192//!             pc.handle_timeout(Instant::now())?;
193//!         }
194//!         // Received network packet
195//!         Ok((n, peer_addr)) = socket.recv_from(&mut buf) => {
196//!             // 5. handle_read() - Feed incoming network packets
197//!             pc.handle_read(TaggedBytesMut {
198//!                 now: Instant::now(),
199//!                 transport: TransportContext {
200//!                     local_addr,
201//!                     peer_addr,
202//!                     ecn: None,
203//!                     transport_protocol: TransportProtocol::UDP,
204//!                 },
205//!                 message: BytesMut::from(&buf[..n]),
206//!             })?;
207//!         }
208//!         // Ctrl-C to exit
209//!         _ = tokio::signal::ctrl_c() => {
210//!             break;
211//!         }
212//!     }
213//! }
214//!
215//! pc.close()?;
216//! # Ok(())
217//! # }
218//! ```
219//!
220//! ## Core API Methods
221//!
222//! ### Sans-I/O Event Loop Methods
223//!
224//! The event loop uses these six core methods:
225//!
226//! 1. **`poll_write()`** - Get outgoing network packets to send via UDP
227//! 2. **`poll_event()`** - Process connection state changes and notifications
228//! 3. **`poll_read()`** - Get incoming application messages (RTP, RTCP, data)
229//! 4. **`poll_timeout()`** - Get next timer deadline for retransmissions/keepalives
230//! 5. **`handle_read()`** - Feed incoming network packets into the connection
231//! 6. **`handle_timeout()`** - Notify about timer expiration
232//!
233//! Additional methods for external control:
234//!
235//! - **`handle_write()`** - Queue application messages (RTP/RTCP/data) for sending
236//! - **`handle_event()`** - Inject external events into the connection
237//!
238//! ### Signaling with Complete Example
239//!
240//! WebRTC requires an external signaling channel to exchange offers, answers, and ICE
241//! candidates. This example shows the complete offer/answer flow:
242//!
243//! ```no_run
244//! use rtc::peer_connection::RTCPeerConnection;
245//! use rtc::peer_connection::configuration::RTCConfigurationBuilder;
246//! use rtc::peer_connection::transport::RTCIceServer;
247//! use rtc::peer_connection::sdp::RTCSessionDescription;
248//! use rtc::peer_connection::transport::{CandidateConfig, CandidateHostConfig, RTCIceCandidate};
249//!
250//! # fn send_to_remote_peer(_: &str) {}
251//! # fn receive_from_remote_peer() -> String { String::new() }
252//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
253//! // Offerer side - creates the offer
254//! let offerer_config = RTCConfigurationBuilder::new()
255//!     .with_ice_servers(vec![RTCIceServer {
256//!         urls: vec!["stun:stun.l.google.com:19302".to_string()],
257//!         ..Default::default()
258//!     }])
259//!     .build();
260//!
261//! let mut offerer = RTCPeerConnection::new(offerer_config)?;
262//!
263//! // 1. Create offer
264//! let offer = offerer.create_offer(None)?;
265//!
266//! // 2. Set local description
267//! offerer.set_local_description(offer.clone())?;
268//!
269//! // 3. Add local ICE candidate
270//! let candidate = CandidateHostConfig {
271//!     base_config: CandidateConfig {
272//!         network: "udp".to_owned(),
273//!         address: "192.168.1.100".to_string(),
274//!         port: 8080,
275//!         component: 1,
276//!         ..Default::default()
277//!     },
278//!     ..Default::default()
279//! }
280//! .new_candidate_host()?;
281//! offerer.add_local_candidate(RTCIceCandidate::from(&candidate).to_json()?)?;
282//!
283//! // 4. Send offer to remote peer (your signaling channel)
284//! send_to_remote_peer(&serde_json::to_string(&offer)?);
285//!
286//! // --- On answerer side ---
287//! let answerer_config = RTCConfigurationBuilder::new()
288//!     .with_ice_servers(vec![RTCIceServer {
289//!         urls: vec!["stun:stun.l.google.com:19302".to_string()],
290//!         ..Default::default()
291//!     }])
292//!     .build();
293//!
294//! let mut answerer = RTCPeerConnection::new(answerer_config)?;
295//!
296//! // 5. Receive and set remote description
297//! let offer_json = receive_from_remote_peer();
298//! let remote_offer: RTCSessionDescription = serde_json::from_str(&offer_json)?;
299//! answerer.set_remote_description(remote_offer)?;
300//!
301//! // 6. Create answer
302//! let answer = answerer.create_answer(None)?;
303//!
304//! // 7. Set local description
305//! answerer.set_local_description(answer.clone())?;
306//!
307//! // 8. Send answer back to offerer
308//! send_to_remote_peer(&serde_json::to_string(&answer)?);
309//!
310//! // --- Back on offerer side ---
311//! // 9. Receive and set remote description
312//! let answer_json = receive_from_remote_peer();
313//! let remote_answer: RTCSessionDescription = serde_json::from_str(&answer_json)?;
314//! offerer.set_remote_description(remote_answer)?;
315//!
316//! // Now both peers are connected!
317//! # Ok(())
318//! # }
319//! ```
320//!
321//! ## Module Organization
322//!
323//! ### [`peer_connection`]
324//!
325//! Core WebRTC peer connection implementation:
326//!
327//! - **[`RTCPeerConnection`](peer_connection::RTCPeerConnection)** - Peer connection interface
328//! - **[`certificate`](peer_connection::certificate)** - Peer connection certficiate
329//! - **[`configuration`](peer_connection::configuration)** - Peer connection configuration
330//!   - **[`interceptor_registry`](peer_connection::configuration::interceptor_registry)** - NACK, TWCC, RTCP Reports configuration
331//!   - **[`media_engine`](peer_connection::configuration::media_engine)** - Codec and RTP extension configuration
332//!   - **[`setting_engine`](peer_connection::configuration::setting_engine)** - Low-level transport settings
333//! - **[`event`](peer_connection::event)** - Peer connection events
334//! - **[`message`](peer_connection::message)** - RTP/RTCP Packets and Application messages
335//! - **[`sdp`](peer_connection::sdp)** - SDP offer/answer types
336//! - **[`state`](peer_connection::state)** - Peer connection state types
337//! - **[`transport`](peer_connection::transport)** - ICE, DTLS, SCTP transport types
338//!
339//! ### [`data_channel`]
340//!
341//! WebRTC data channels for arbitrary data transfer:
342//!
343//! - **[`RTCDataChannel`](data_channel::RTCDataChannel)** - Data channel interface
344//! - **[`RTCDataChannelInit`](data_channel::RTCDataChannelInit)** - Channel configuration
345//! - **[`RTCDataChannelMessage`](data_channel::RTCDataChannelMessage)** - Data channel messages
346//!
347//! ### [`rtp_transceiver`]
348//!
349//! RTP media transmission and reception:
350//!
351//! - **[`RTCRtpSender`](rtp_transceiver::rtp_sender::RTCRtpSender)** - Media sender
352//! - **[`RTCRtpReceiver`](rtp_transceiver::rtp_receiver::RTCRtpReceiver)** - Media receiver
353//!
354//! ### [`media_stream`]
355//!
356//! Media track management:
357//!
358//! - **[`MediaStreamTrack`](media_stream::track::MediaStreamTrack)** - Audio/video track
359//!
360//! ## Features
361//!
362//! - ✅ **ICE (Interactive Connectivity Establishment)** - NAT traversal with STUN/TURN
363//! - ✅ **DTLS (Datagram Transport Layer Security)** - Encryption for media and data
364//! - ✅ **SCTP (Stream Control Transmission Protocol)** - Reliable data channels
365//! - ✅ **RTP/RTCP** - Real-time media transport and control
366//! - ✅ **SDP (Session Description Protocol)** - Offer/answer negotiation
367//! - ✅ **Data Channels** - Bidirectional peer-to-peer data transfer
368//! - ✅ **Media Tracks** - Audio/video transmission
369//! - ✅ **Trickle ICE** - Progressive candidate gathering
370//! - ✅ **ICE Restart** - Connection recovery
371//! - ✅ **Simulcast & SVC** - Scalable video coding
372//!
373//! ## Working Examples
374//!
375//! The crate includes comprehensive examples in the `examples/` directory:
376//!
377//! - **data-channels-offer-answer** - Complete data channel setup with signaling
378//! - **save-to-disk-vpx** - Receive and save VP8/VP9 video to disk
379//! - **play-from-disk-vpx** - Send VP8/VP9 video from disk
380//! - **rtp-forwarder** - Forward RTP streams between peers
381//! - **simulcast** - Multiple quality streams
382//! - **trickle-ice** - Progressive ICE candidate exchange
383//!
384//! See the `examples/` directory for complete, runnable code.
385//!
386//! ## Common Patterns
387//!
388//! ### Configuring Interceptors (NACK, TWCC, RTCP Reports)
389//!
390//! Interceptors process RTP/RTCP packets as they flow through the media pipeline.
391//! Use the [`interceptor_registry`](peer_connection::configuration::interceptor_registry) module
392//! to configure packet loss recovery, congestion control, and quality monitoring:
393//!
394//! ```no_run
395//! use rtc::peer_connection::RTCPeerConnection;
396//! use rtc::peer_connection::configuration::RTCConfigurationBuilder;
397//! use rtc::peer_connection::configuration::media_engine::MediaEngine;
398//! use rtc::peer_connection::configuration::interceptor_registry::register_default_interceptors;
399//! use rtc::interceptor::Registry;
400//!
401//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
402//! // Create media engine with default codecs
403//! let mut media_engine = MediaEngine::default();
404//!
405//! // Create interceptor registry with default interceptors:
406//! // - NACK: Packet loss recovery for video
407//! // - RTCP Reports: Sender/Receiver quality statistics
408//! // - TWCC Receiver: Congestion control feedback
409//! let registry = Registry::new();
410//! let registry = register_default_interceptors(registry, &mut media_engine)?;
411//!
412//! // Build configuration with interceptors
413//! let config = RTCConfigurationBuilder::new()
414//!     .with_media_engine(media_engine)
415//!     .with_interceptor_registry(registry)
416//!     .build();
417//!
418//! let mut pc = RTCPeerConnection::new(config)?;
419//! # Ok(())
420//! # }
421//! ```
422//!
423//! For custom interceptor configuration:
424//!
425//! ```no_run
426//! use rtc::peer_connection::RTCPeerConnection;
427//! use rtc::peer_connection::configuration::RTCConfigurationBuilder;
428//! use rtc::peer_connection::configuration::media_engine::MediaEngine;
429//! use rtc::peer_connection::configuration::interceptor_registry::{
430//!     configure_nack,
431//!     configure_rtcp_reports,
432//!     configure_twcc,
433//! };
434//! use rtc::interceptor::Registry;
435//!
436//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
437//! let mut media_engine = MediaEngine::default();
438//! let registry = Registry::new();
439//!
440//! // Configure individual interceptors as needed
441//! let registry = configure_nack(registry, &mut media_engine);      // Packet loss recovery
442//! let registry = configure_rtcp_reports(registry);                   // SR/RR statistics
443//! let registry = configure_twcc(registry, &mut media_engine)?;       // Full TWCC (sender + receiver)
444//!
445//! let config = RTCConfigurationBuilder::new()
446//!     .with_media_engine(media_engine)
447//!     .with_interceptor_registry(registry)
448//!     .build();
449//!
450//! let mut pc = RTCPeerConnection::new(config)?;
451//! # Ok(())
452//! # }
453//! ```
454//!
455//! ### Creating and Using Data Channels
456//!
457//! ```no_run
458//! use rtc::peer_connection::RTCPeerConnection;
459//! use rtc::peer_connection::configuration::RTCConfiguration;
460//! use rtc::data_channel::RTCDataChannelInit;
461//! use rtc::peer_connection::event::RTCPeerConnectionEvent;
462//! use rtc::peer_connection::message::RTCMessage;
463//! use rtc::sansio::Protocol;
464//! use bytes::BytesMut;
465//!
466//! # fn example(mut pc: RTCPeerConnection) -> Result<(), Box<dyn std::error::Error>> {
467//! // Create data channel with ordered, reliable delivery
468//! let init = RTCDataChannelInit {
469//!     ordered: true,
470//!     max_retransmits: None,
471//!     ..Default::default()
472//! };
473//!
474//! let mut dc = pc.create_data_channel("my-channel", Some(init))?;
475//! let channel_id = dc.id();
476//!
477//! // Send text message
478//! dc.send_text("Hello, WebRTC!")?;
479//!
480//! // Send binary message
481//! dc.send(BytesMut::from(&[0x01, 0x02, 0x03, 0x04][..]))?;
482//!
483//! // Later, retrieve the data channel by ID
484//! if let Some(mut dc) = pc.data_channel(channel_id) {
485//!     dc.send_text("Another message")?;
486//! }
487//!
488//! // Receive messages in event loop
489//! while let Some(message) = pc.poll_read() {
490//!     if let RTCMessage::DataChannelMessage(channel_id, msg) = message {
491//!         if msg.is_string {
492//!             let text = String::from_utf8_lossy(&msg.data);
493//!             println!("Received text: {text}");
494//!         } else {
495//!             println!("Received binary: {} bytes", msg.data.len());
496//!         }
497//!     }
498//! }
499//! # Ok(())
500//! # }
501//! ```
502//!
503//! ### Adding Media Tracks with Codecs
504//!
505//! ```no_run
506//! use rtc::peer_connection::RTCPeerConnection;
507//! use rtc::media_stream::MediaStreamTrack;
508//! use rtc::rtp_transceiver::rtp_sender::{RTCRtpCodec, RTCRtpCodecParameters, RtpCodecKind};
509//! use rtc::rtp_transceiver::rtp_sender::{RTCRtpEncodingParameters, RTCRtpCodingParameters};
510//! use rtc::peer_connection::configuration::media_engine::{MIME_TYPE_VP8, MIME_TYPE_OPUS};
511//!
512//! # fn example(mut pc: RTCPeerConnection) -> Result<(), Box<dyn std::error::Error>> {
513//! // Configure VP8 video codec
514//! let video_codec = RTCRtpCodec {
515//!     mime_type: MIME_TYPE_VP8.to_owned(),
516//!     clock_rate: 90000,
517//!     channels: 0,
518//!     sdp_fmtp_line: "".to_owned(),
519//!     rtcp_feedback: vec![],
520//! };
521//!
522//! // Create video track
523//! let video_track = MediaStreamTrack::new(
524//!     "stream-id".to_string(),
525//!     "video-track-id".to_string(),
526//!     "video-label".to_string(),
527//!     RtpCodecKind::Video,
528//!     vec![RTCRtpEncodingParameters {
529//!         rtp_coding_parameters: RTCRtpCodingParameters {
530//!             ssrc: Some(rand::random::<u32>()),
531//!             ..Default::default()
532//!         },
533//!         codec: video_codec.clone(),
534//!         ..Default::default()
535//!     }],
536//! );
537//!
538//! // Add track to peer connection
539//! let sender_id = pc.add_track(video_track)?;
540//!
541//! // Send RTP packets
542//! if let Some(mut sender) = pc.rtp_sender(sender_id) {
543//!     // sender.write_rtp(rtp_packet)?;
544//! }
545//! # Ok(())
546//! # }
547//! ```
548//!
549//! ### Receiving Media Tracks
550//!
551//! ```no_run
552//! use rtc::peer_connection::RTCPeerConnection;
553//! use rtc::peer_connection::event::{RTCPeerConnectionEvent, RTCTrackEvent};
554//! use rtc::peer_connection::message::RTCMessage;
555//! use rtc::sansio::Protocol;
556//! use std::collections::HashMap;
557//!
558//! # fn example(mut pc: RTCPeerConnection) -> Result<(), Box<dyn std::error::Error>> {
559//! // Track mapping for received tracks
560//! let mut track_to_receiver = HashMap::new();
561//!
562//! // Handle track events
563//! while let Some(event) = pc.poll_event() {
564//!     if let RTCPeerConnectionEvent::OnTrack(track_event) = event {
565//!         match track_event {
566//!             RTCTrackEvent::OnOpen(init) => {
567//!                 println!("New track: track_id={}, receiver_id={:?}",
568//!                     init.track_id, init.receiver_id);
569//!                 track_to_receiver.insert(init.track_id.clone(), init.receiver_id);
570//!             }
571//!             RTCTrackEvent::OnClose(track_id) => {
572//!                 println!("Track closed: {track_id}");
573//!                 track_to_receiver.remove(&track_id);
574//!             }
575//!             _ => {}
576//!         }
577//!     }
578//! }
579//!
580//! // Receive RTP packets
581//! while let Some(message) = pc.poll_read() {
582//!     if let RTCMessage::RtpPacket(track_id, rtp_packet) = message {
583//!         println!("RTP packet on track {}: {} bytes",
584//!             track_id, rtp_packet.payload.len());
585//!         
586//!         // Access receiver to get track metadata
587//!         if let Some(&receiver_id) = track_to_receiver.get(&track_id) {
588//!             if let Some(receiver) = pc.rtp_receiver(receiver_id) {
589//!                 let track = receiver.track();
590//!                 let ssrcs: Vec<u32> = track.ssrcs().collect();
591//!                 println!("  SSRCs: {:?}, Kind: {:?}", ssrcs, track.kind());
592//!             }
593//!         }
594//!     }
595//! }
596//! # Ok(())
597//! # }
598//! ```
599//!
600//! ### Sending RTCP Packets (e.g., PLI for keyframes)
601//!
602//! ```no_run
603//! use rtc::peer_connection::RTCPeerConnection;
604//! use rtc::rtp_transceiver::RTCRtpReceiverId;
605//! use rtc::rtcp::payload_feedbacks::picture_loss_indication::PictureLossIndication;
606//!
607//! # fn example(mut pc: RTCPeerConnection, receiver_id: RTCRtpReceiverId, media_ssrc: u32)
608//! #     -> Result<(), Box<dyn std::error::Error>> {
609//! // Request keyframe by sending Picture Loss Indication (PLI)
610//! if let Some(mut receiver) = pc.rtp_receiver(receiver_id) {
611//!     receiver.write_rtcp(vec![Box::new(PictureLossIndication {
612//!         sender_ssrc: 0,
613//!         media_ssrc,
614//!     })])?;
615//! }
616//! # Ok(())
617//! # }
618//! ```
619//!
620//! ## Specification Compliance
621//!
622//! This implementation follows these specifications:
623//!
624//! - [W3C WebRTC 1.0] - Main WebRTC API specification
625//! - [RFC 8829] - JSEP: JavaScript Session Establishment Protocol  
626//! - [RFC 8866] - SDP: Session Description Protocol
627//! - [RFC 8445] - ICE: Interactive Connectivity Establishment
628//! - [RFC 6347] - DTLS: Datagram Transport Layer Security
629//! - [RFC 8831] - WebRTC Data Channels
630//! - [RFC 3550] - RTP: Real-time Transport Protocol
631//!
632//! [W3C WebRTC 1.0]: https://www.w3.org/TR/webrtc/
633//! [RFC 8829]: https://datatracker.ietf.org/doc/html/rfc8829
634//! [RFC 8866]: https://datatracker.ietf.org/doc/html/rfc8866
635//! [RFC 8445]: https://datatracker.ietf.org/doc/html/rfc8445
636//! [RFC 6347]: https://datatracker.ietf.org/doc/html/rfc6347
637//! [RFC 8831]: https://datatracker.ietf.org/doc/html/rfc8831
638//! [RFC 3550]: https://datatracker.ietf.org/doc/html/rfc3550
639//!
640//! ## Further Reading
641//!
642//! - [Sans-I/O Approach](https://sans-io.readthedocs.io/) - Detailed explanation of sans-I/O design
643//! - [WebRTC for the Curious](https://webrtcforthecurious.com/) - Comprehensive WebRTC guide
644//! - [MDN WebRTC API](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API) - Browser WebRTC documentation
645
646#![doc(
647    html_logo_url = "https://raw.githubusercontent.com/webrtc-rs/webrtc-rs.github.io/master/res/rtc.png"
648)]
649#![warn(rust_2018_idioms)]
650#![allow(dead_code)]
651
652pub use {
653    datachannel, dtls, ice, interceptor, mdns, media, rtcp, rtp, sansio, sctp, sdp, shared, srtp,
654    stun, turn,
655};
656
657pub mod data_channel;
658pub mod media_stream;
659pub mod peer_connection;
660pub mod rtp_transceiver;
661pub mod statistics;