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;