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