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;