Skip to main content

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