str0m/
lib.rs

1//! <image src="https://user-images.githubusercontent.com/227204/226143511-66fe5264-6ab7-47b9-9551-90ba7e155b96.svg" alt="str0m logo" ></image>
2//!
3//! A Sans I/O WebRTC implementation in Rust.
4//!
5//! This is a [Sans I/O][sansio] implementation meaning the `Rtc` instance itself is not doing any network
6//! talking. Furthermore it has no internal threads or async tasks. All operations are happening from the
7//! calls of the public API.
8//!
9//! This is deliberately not a standard `RTCPeerConnection` API since that isn't a great fit for Rust.
10//! See more details in below section.
11//!
12//! # Join us
13//!
14//! We are discussing str0m things on Zulip. Join us using this [invitation link][zulip]. Or browse the
15//! discussions anonymously at [str0m.zulipchat.com][zulip-anon]
16//!
17//! <image width="300px" src="https://user-images.githubusercontent.com/227204/209446544-f8a8d673-cb1b-4144-a0f2-42307b8d8869.gif" alt="silly clip showing video playing" ></image>
18//!
19//! # Usage
20//!
21//! The [`chat`][x-chat] example shows how to connect multiple browsers
22//! together and act as an SFU (Selective Forwarding Unit). The example
23//! multiplexes all traffic over one server UDP socket and uses two threads
24//! (one for the web server, and one for the SFU loop).
25//!
26//! ## TLS
27//!
28//! For the browser to do WebRTC, all traffic must be under TLS. The
29//! project ships with a self-signed certificate that is used for the
30//! examples. The certificate is for hostname `str0m.test` since TLD .test
31//! should never resolve to a real DNS name.
32//!
33//! ```text
34//! cargo run --example chat
35//! ```
36//!
37//! The log should prompt you to connect a browser to https://10.0.0.103:3000 – this will
38//! most likely cause a security warning that you must get the browser to accept.
39//!
40//! The [`http-post`][x-post] example roughly illustrates how to receive
41//! media data from a browser client. The example is single threaded and
42//! is a bit simpler than the chat. It is a good starting point to understand the API.
43//!
44//! ```text
45//! cargo run --example http-post
46//! ```
47//!
48//! ### Real example
49//!
50//! To see how str0m is used in a real project, check out [BitWHIP][bitwhip] –
51//! a CLI WebRTC Agent written in Rust.
52//!
53//! ## Passive
54//!
55//! For passive connections, i.e. where the media and initial OFFER is
56//! made by a remote peer, we need these steps to open the connection.
57//!
58//! ```no_run
59//! # use str0m::{Rtc, Candidate};
60//! // Instantiate a new Rtc instance.
61//! let mut rtc = Rtc::new();
62//!
63//! //  Add some ICE candidate such as a locally bound UDP port.
64//! let addr = "1.2.3.4:5000".parse().unwrap();
65//! let candidate = Candidate::host(addr, "udp").unwrap();
66//! rtc.add_local_candidate(candidate);
67//!
68//! // Accept an incoming offer from the remote peer
69//! // and get the corresponding answer.
70//! let offer = todo!();
71//! let answer = rtc.sdp_api().accept_offer(offer).unwrap();
72//!
73//! // Forward the answer to the remote peer.
74//!
75//! // Go to _run loop_
76//! ```
77//!
78//! ## Active
79//!
80//! Active connections means we are making the inital OFFER and waiting for a
81//! remote ANSWER to start the connection.
82//!
83//! ```no_run
84//! # use str0m::{Rtc, Candidate};
85//! # use str0m::media::{MediaKind, Direction};
86//! // Instantiate a new Rtc instance.
87//! let mut rtc = Rtc::new();
88//!
89//! // Add some ICE candidate such as a locally bound UDP port.
90//! let addr = "1.2.3.4:5000".parse().unwrap();
91//! let candidate = Candidate::host(addr, "udp").unwrap();
92//! rtc.add_local_candidate(candidate);
93//!
94//! // Create a `SdpApi`. The change lets us make multiple changes
95//! // before sending the offer.
96//! let mut change = rtc.sdp_api();
97//!
98//! // Do some change. A valid OFFER needs at least one "m-line" (media).
99//! let mid = change.add_media(MediaKind::Audio, Direction::SendRecv, None, None, None);
100//!
101//! // Get the offer.
102//! let (offer, pending) = change.apply().unwrap();
103//!
104//! // Forward the offer to the remote peer and await the answer.
105//! // How to transfer this is outside the scope for this library.
106//! let answer = todo!();
107//!
108//! // Apply answer.
109//! rtc.sdp_api().accept_answer(pending, answer).unwrap();
110//!
111//! // Go to _run loop_
112//! ```
113//!
114//! ## Run loop
115//!
116//! Driving the state of the `Rtc` forward is a run loop that, regardless of sync or async,
117//! looks like this.
118//!
119//! ```no_run
120//! # use str0m::{Rtc, Output, IceConnectionState, Event, Input};
121//! # use str0m::net::{Receive, Protocol};
122//! # use std::io::ErrorKind;
123//! # use std::net::UdpSocket;
124//! # use std::time::Instant;
125//! # let rtc = Rtc::new();
126//! // Buffer for reading incoming UDP packets.
127//! let mut buf = vec![0; 2000];
128//!
129//! // A UdpSocket we obtained _somehow_.
130//! let socket: UdpSocket = todo!();
131//!
132//! loop {
133//!     // Poll output until we get a timeout. The timeout means we
134//!     // are either awaiting UDP socket input or the timeout to happen.
135//!     let timeout = match rtc.poll_output().unwrap() {
136//!         // Stop polling when we get the timeout.
137//!         Output::Timeout(v) => v,
138//!
139//!         // Transmit this data to the remote peer. Typically via
140//!         // a UDP socket. The destination IP comes from the ICE
141//!         // agent. It might change during the session.
142//!         Output::Transmit(v) => {
143//!             socket.send_to(&v.contents, v.destination).unwrap();
144//!             continue;
145//!         }
146//!
147//!         // Events are mainly incoming media data from the remote
148//!         // peer, but also data channel data and statistics.
149//!         Output::Event(v) => {
150//!
151//!             // Abort if we disconnect.
152//!             if v == Event::IceConnectionStateChange(IceConnectionState::Disconnected) {
153//!                 return;
154//!             }
155//!
156//!             // TODO: handle more cases of v here, such as incoming media data.
157//!
158//!             continue;
159//!         }
160//!     };
161//!
162//!     // Duration until timeout.
163//!     let duration = timeout - Instant::now();
164//!
165//!     // socket.set_read_timeout(Some(0)) is not ok
166//!     if duration.is_zero() {
167//!         // Drive time forwards in rtc straight away.
168//!         rtc.handle_input(Input::Timeout(Instant::now())).unwrap();
169//!         continue;
170//!     }
171//!
172//!     socket.set_read_timeout(Some(duration)).unwrap();
173//!
174//!     // Scale up buffer to receive an entire UDP packet.
175//!     buf.resize(2000, 0);
176//!
177//!     // Try to receive. Because we have a timeout on the socket,
178//!     // we will either receive a packet, or timeout.
179//!     // This is where having an async loop shines. We can await multiple things to
180//!     // happen such as outgoing media data, the timeout and incoming network traffic.
181//!     // When using async there is no need to set timeout on the socket.
182//!     let input = match socket.recv_from(&mut buf) {
183//!         Ok((n, source)) => {
184//!             // UDP data received.
185//!             buf.truncate(n);
186//!             Input::Receive(
187//!                 Instant::now(),
188//!                 Receive {
189//!                     proto: Protocol::Udp,
190//!                     source,
191//!                     destination: socket.local_addr().unwrap(),
192//!                     contents: buf.as_slice().try_into().unwrap(),
193//!                 },
194//!             )
195//!         }
196//!
197//!         Err(e) => match e.kind() {
198//!             // Expected error for set_read_timeout().
199//!             // One for windows, one for the rest.
200//!             ErrorKind::WouldBlock
201//!                 | ErrorKind::TimedOut => Input::Timeout(Instant::now()),
202//!
203//!             e => {
204//!                 eprintln!("Error: {:?}", e);
205//!                 return; // abort
206//!             }
207//!         },
208//!     };
209//!
210//!     // Input is either a Timeout or Receive of data. Both drive the state forward.
211//!     rtc.handle_input(input).unwrap();
212//! }
213//! ```
214//!
215//! ## Sending media data
216//!
217//! When creating the media, we can decide which codecs to support, and they
218//! are negotiated with the remote side. Each codec corresponds to a
219//! "payload type" (PT). To send media data we need to figure out which PT
220//! to use when sending.
221//!
222//! ```no_run
223//! # use str0m::Rtc;
224//! # use str0m::media::Mid;
225//! # let rtc: Rtc = todo!();
226//! // Obtain mid from Event::MediaAdded
227//! let mid: Mid = todo!();
228//!
229//! // Create a media writer for the mid.
230//! let writer = rtc.writer(mid).unwrap();
231//!
232//! // Get the payload type (pt) for the wanted codec.
233//! let pt = writer.payload_params().nth(0).unwrap().pt();
234//!
235//! // Write the data
236//! let wallclock = todo!();   // Absolute time of the data
237//! let media_time = todo!();  // Media time, in RTP time
238//! let data: &[u8] = todo!(); // Actual data
239//! writer.write(pt, wallclock, media_time, data).unwrap();
240//! ```
241//!
242//! ## Media time, wallclock and local time
243//!
244//! str0m has three main concepts of time. "now", media time and wallclock.
245//!
246//! ### Now
247//!
248//! Some calls in str0m, such as `Rtc::handle_input` takes a `now` argument
249//! that is a `std::time::Instant`. These calls "drive the time forward" in
250//! the internal state. This is used for everything like deciding when
251//! to produce various feedback reports (RTCP) to remote peers, to
252//! bandwidth estimation (BWE) and statistics.
253//!
254//! Str0m has _no internal clock_ calls. I.e. str0m never calls
255//! `Instant::now()` itself. All time is external input. That means it's
256//! possible to construct test cases driving an `Rtc` instance faster
257//! than realtime (see the [integration tests][intg]).
258//!
259//! ### Media time
260//!
261//! Each RTP header has a 32 bit number that str0m calls _media time_.
262//! Media time is in some time base that is dependent on the codec,
263//! however all codecs in str0m use 90_000Hz for video and 48_000Hz
264//! for audio.
265//!
266//! For video the `MediaTime` type is `<timestamp>/90_000` str0m extends
267//! the 32 bit number in the RTP header to 64 bit taking into account
268//! "rollover". 64 bit is such a large number the user doesn't need to
269//! think about rollovers.
270//!
271//! ### Wallclock
272//!
273//! With _wallclock_ str0m means the time a sample of media was produced
274//! at an originating source. I.e. if we are talking into a microphone the
275//! wallclock is the NTP time the sound is sampled.
276//!
277//! We can't know the exact wallclock for media from a remote peer since
278//! not every device is synchronized with NTP. Every sender does
279//! periodically produce a Sender Report (SR) that contains the peer's
280//! idea of its wallclock, however this number can be very wrong compared to
281//! "real" NTP time.
282//!
283//! Furthermore, not all remote devices will have a linear idea of
284//! time passing that exactly matches the local time. A minute on the
285//! remote peer might not be exactly one minute locally.
286//!
287//! These timestamps become important when handling simultaneous audio from
288//! multiple peers.
289//!
290//! When writing media we need to provide str0m with an estimated wallclock.
291//! The simplest strategy is to only trust local time and use arrival time
292//! of the incoming UDP packet. Another simple strategy is to lock some
293//! time T at the first UDP packet, and then offset each wallclock using
294//! `MediaTime`, i.e. for video we could have `T + <media time>/90_000`
295//!
296//! A production worthy SFU probably needs an even more sophisticated
297//! strategy weighing in all possible time sources to get a good estimate
298//! of the remote wallclock for a packet.
299//!
300//! # Crypto backends
301//!
302//! str0m has two crypto backends, `openssl` and `wincrypto`. The default is
303//! `openssl` which works on all platforms (also Windows). Ideally we want a
304//! pure rust version of the crypto code, but WebRTC currently requires
305//! DTLS 1.2 (not the latest version 1.3), and that leaves us only with a
306//! few possible options.
307//!
308//! When compiling for Windows, the `openssl` feature can be removed and
309//! only rely on `wincrypto`. However notice that `str0m` never picks up a
310//! default automatically, you must explicitly configure the crypto backend,
311//! also when removing the `openssl` feature.
312//!
313//! If you are building an application, the easiest is to set the default
314//! for the entire process.
315//!
316//! ```no_run
317//! use str0m::config::CryptoProvider;
318//!
319//! // Will panic if run twice
320//! CryptoProvider::WinCrypto.install_process_default();
321//! ```
322//!
323//! # Project status
324//!
325//! Str0m was originally developed by Martin Algesten of
326//! [Lookback][lookback]. We use str0m for a specific use case: str0m as a
327//! server SFU (as opposed to peer-2-peer). That means we are heavily
328//! testing and developing the parts needed for our use case. Str0m is
329//! intended to be an all-purpose WebRTC library, which means it also
330//! works for peer-2-peer, though that aspect has received less testing.
331//!
332//! Performance is very good, there have been some work the discover and
333//! optimize bottlenecks. Such efforts are of course never ending with
334//! diminishing returns. While there are no glaringly obvious performance
335//! bottlenecks, more work is always welcome – both algorithmically and
336//! allocation/cloning in hot paths etc.
337//!
338//! # Design
339//!
340//! Output from the `Rtc` instance can be grouped into three kinds.
341//!
342//! 1. Events (such as receiving media or data channel data).
343//! 2. Network output. Data to be sent, typically from a UDP socket.
344//! 3. Timeouts. Indicates when the instance next expects a time input.
345//!
346//! Input to the `Rtc` instance is:
347//!
348//! 1. User operations (such as sending media or data channel data).
349//! 2. Network input. Typically read from a UDP socket.
350//! 3. Timeouts. As obtained from the output above.
351//!
352//! The correct use can be seen in the above [Run loop](#run-loop) or in the
353//! examples.
354//!
355//! Sans I/O is a pattern where we turn both network input/output as well
356//! as time passing into external input to the API. This means str0m has
357//! no internal threads, just an enormous state machine that is driven
358//! forward by different kinds of input.
359//!
360//! ## Sample or RTP level?
361//!
362//! Str0m defaults to the "sample level" which treats the RTP as an internal detail. The user
363//! will thus mainly interact with:
364//!
365//! 1. [`Event::MediaData`][evmed] to receive full "samples" (audio frames or video frames).
366//! 2. [`Writer::write`][writer] to write full samples.
367//! 3. [`Writer::request_keyframe`][reqkey] to request keyframes.
368//!
369//! ### Sample level
370//!
371//! All codecs such as h264, vp8, vp9 and opus outputs what we call
372//! "Samples". A sample has a very specific meaning for audio, but this
373//! project uses it in a broader sense, where a sample is either a video
374//! or audio time stamped chunk of encoded data that typically represents
375//! a chunk of audio, or _one single frame for video_.
376//!
377//! Samples are not suitable to use directly in UDP (RTP) packets - for
378//! one they are too big. Samples are therefore further chunked up by
379//! codec specific payloaders into RTP packets.
380//!
381//! ### RTP mode
382//!
383//! Str0m also provides an RTP level API. This would be similar to many other
384//! RTP libraries where the RTP packets themselves are the the API surface
385//! towards the user (when building an SFU one would often talk about "forwarding
386//! RTP packets", while with str0m we can also "forward samples").  Using
387//! this API requires a deeper knowledge of RTP and WebRTC.
388//!
389//! To enable RTP mode
390//!
391//! ```
392//! # #[cfg(feature = "openssl")] {
393//! # use str0m::Rtc;
394//! let rtc = Rtc::builder()
395//!     // Enable RTP mode for this Rtc instance.
396//!     // This disables `MediaEvent` and the `Writer::write` API.
397//!     .set_rtp_mode(true)
398//!     .build();
399//! # }
400//! ```
401//!
402//! RTP mode gives us some new API points.
403//!
404//! 1. [`Event::RtpPacket`][rtppak] emitted for every incoming RTP packet. Empty packets for bandwidth
405//!    estimation are silently discarded.
406//! 2. [`StreamTx::write_rtp`][wrtrtp] to write outgoing RTP packets.
407//! 3. [`StreamRx::request_keyframe`][reqkey2] to request keyframes from remote.
408//!
409//! ## NIC enumeration and TURN (and STUN)
410//!
411//! The [ICE RFC][ice] talks about "gathering ice candidates". This means
412//! inspecting the local network interfaces and potentially binding UDP
413//! sockets on each usable interface. Since str0m is Sans I/O, this part
414//! is outside the scope of what str0m does. How the user figures out
415//! local IP addresses, via config or via looking up local NICs is not
416//! something str0m cares about.
417//!
418//! TURN is a way of obtaining IP addresses that can be used as fallback
419//! in case direct connections fail. We consider TURN similar to
420//! enumerating local network interfaces – it's a way of obtaining
421//! sockets.
422//!
423//! All discovered candidates, be they local (NIC) or remote sockets
424//! (TURN), are added to str0m and str0m will perform the task of ICE
425//! agent, forming "candidate pairs" and figuring out the best connection
426//! while the actual task of sending the network traffic is left to the
427//! user.
428//!
429//! ## The importance of `&mut self`
430//!
431//! Rust shines when we can eschew locks and heavily rely `&mut` for data
432//! write access. Since str0m has no internal threads, we never have to
433//! deal with shared data. Furthermore the the internals of the library is
434//! organized such that we don't need multiple references to the same
435//! entities. In str0m there are no `Rc`, `Mutex`, `mpsc`, `Arc`(*),  or
436//! other locks.
437//!
438//! This means all input to the lib can be modelled as
439//! `handle_something(&mut self, something)`.
440//!
441//! (*) Ok. There is one `Arc` if you use Windows where we also require openssl.
442//!
443//! ## Not a standard WebRTC "Peer Connection" API
444//!
445//! The library deliberately steps away from the "standard" WebRTC API as
446//! seen in JavaScript and/or [webrtc-rs][webrtc-rs] (or [Pion][pion] in Go).
447//! There are few reasons for this.
448//!
449//! First, in the standard API, events are callbacks, which are not a
450//! great fit for Rust. Callbacks require some kind of reference
451//! (ownership?) over the entity the callback is being dispatched
452//! upon. I.e. if in Rust we want `pc.addEventListener(x)`, `x` needs
453//! to be wholly owned by `pc`, or have some shared reference (like
454//! `Arc`). Shared references means shared data, and to get mutable shared
455//! data, we will need some kind of lock. i.e. `Arc<Mutex<EventListener>>`
456//! or similar.
457//!
458//! As an alternative we could turn all events into `mpsc` channels, but
459//! listening to multiple channels is awkward without async.
460//!
461//! Second, in the standard API, entities like `RTCPeerConnection` and
462//! `RTCRtpTransceiver`, are easily clonable and/or long lived
463//! references. I.e. `pc.getTranscievers()` returns objects that can be
464//! retained and owned by the caller. This pattern is fine for garbage
465//! collected or reference counted languages, but not great with Rust.
466//!
467//! ## Panics, Errors and unwraps
468//!
469//! Str0m adheres to [fail-fast][ff]. That means rather than brushing state
470//! bugs under the carpet, it panics. We make a distinction between errors and
471//! bugs.
472//!
473//! * Errors are as a result of incorrect or impossible to understand user input.
474//! * Bugs are broken internal invariants (assumptions).
475//!
476//! If you scan the str0m code you find a few `unwrap()` (or `expect()`). These
477//! will (should) always be accompanied by a code comment that explains why the
478//! unwrap is okay. This is an internal invariant, a state assumption that
479//! str0m is responsible for maintaining.
480//!
481//! We do not believe it's correct to change every `unwrap()`/`expect()` into
482//! `unwrap_or_else()`, `if let Some(x) = x { ... }` etc, because doing so
483//! brushes an actual problem (an incorrect assumption) under the carpet. Trying
484//! to hobble along with an incorrect state would at best result in broken
485//! behavior, at worst a security risk!
486//!
487//! Panics are our friends: *panic means bug*
488//!
489//! And also: str0m should *never* panic on any user input. If you encounter a panic,
490//! please report it!
491//!
492//! ### Catching panics
493//!
494//! Panics should be incredibly rare, or we have a serious problem as a project. For an SFU,
495//! it might not be ideal if str0m encounters a bug and brings the entire server down with it.
496//!
497//! For those who want an extra level of safety, we recommend looking at [`catch_unwind`][catch]
498//! to safely discard a faulty `Rtc` instance. Since `Rtc` has no internal threads, locks or async
499//! tasks, discarding the instance never risk poisoning locks or other issues that can happen
500//! when catching a panic.
501//!
502//! ## FAQ
503//!
504//! ### Features
505//!
506//! Below is a brief comparison of features between libWebRTC and str0m to help you determine
507//! if str0m is suitable for your project.
508//!
509//! | Feature                  | str0m              | libWebRTC          |
510//! | ------------------------ | ------------------ | ------------------ |
511//! | Peer Connection API      | :x:                | :white_check_mark: |
512//! | SDP                      | :white_check_mark: | :white_check_mark: |
513//! | ICE                      | :white_check_mark: | :white_check_mark: |
514//! | Data Channels            | :white_check_mark: | :white_check_mark: |
515//! | Send/Recv Reports        | :white_check_mark: | :white_check_mark: |
516//! | Transport Wide CC        | :white_check_mark: | :white_check_mark: |
517//! | Bandwidth Estimation     | :white_check_mark: | :white_check_mark: |
518//! | Simulcast                | :white_check_mark: | :white_check_mark: |
519//! | NACK                     | :white_check_mark: | :white_check_mark: |
520//! | Packetize                | :white_check_mark: | :white_check_mark: |
521//! | Fixed Depacketize Buffer | :white_check_mark: | :white_check_mark: |
522//! | Adaptive Jitter Buffer   | :x:                | :white_check_mark: |
523//! | Video/audio capture      | :x:                | :white_check_mark: |
524//! | Video/audio encode       | :x:                | :white_check_mark: |
525//! | Video/audio decode       | :x:                | :white_check_mark: |
526//! | Audio render             | :x:                | :white_check_mark: |
527//! | Turn                     | :x:                | :white_check_mark: |
528//! | Network interface enum   | :x:                | :white_check_mark: |
529//!
530//! ### Platform Support
531//!
532//! Platforms str0m is compiled and tested on:
533//!
534//! | Platform                   | Compiled          | Tested            |
535//! | -------------------------- | ----------------- | ----------------- |
536//! | `x86_64-pc-windows-msvc`   | :white_check_mark:| :white_check_mark:|
537//! | `x86_64-unknown-linux-gnu` | :white_check_mark:| :white_check_mark:|
538//! | `x86_64-apple-darwin`      | :white_check_mark:| :white_check_mark:|
539//!
540//! If your platform isn't listed but is supported by Rust, we'd love for you to give str0m a try and
541//! share your experience. We greatly appreciate your feedback!
542//!
543//! ### Does str0m support IPv4, IPv6, UDP and TCP?
544//!
545//! Certainly! str0m fully support IPv4, IPv6, UDP and TCP protocols.
546//!
547//! ### Can I utilize str0m with any Rust async runtime?
548//!
549//! Absolutely! str0m is fully sync, ensuring that it integrates seamlessly with any Rust async
550//! runtime you opt for.
551//!
552//! ### Can I create a client with str0m?
553//!
554//! Of course! You have the freedom to create a client with str0m. However, please note that some
555//! common client features like media encoding, decoding, and capture are not included in str0m. But
556//! don't let that stop you from building amazing applications!
557//!
558//! ### Can I use str0m in a media server?
559//!
560//! Yes! str0m excels as a server component with support for both RTP API and Sample API. You can
561//! easily build that recording server or SFU you dreamt of in Rust!
562//!
563//! ### Can I deploy the chat example into production?
564//!
565//! While the chat example showcases how to use str0m's API, it's not intended for production use or
566//! heavy load. Writing a full-featured SFU or MCU (Multipoint Control Unit) is a significant
567//! undertaking, involving various design decisions based on production requirements.
568//!
569//! ### Discovered a bug? Here's how to share it with us
570//!
571//! We'd love to hear about it! Please submit an issue and consider joining our Zulip community
572//! to discuss further. For a seamless reporting experience, refer to this exemplary
573//! bug report: <https://github.com/algesten/str0m/issues/382>. We appreciate your contribution
574//! to making str0m better!
575//!
576//! ### I am allergic to SDP can you help me?
577//!
578//! Yes use the direct API!
579//!
580//! [sansio]:     https://sans-io.readthedocs.io
581//! [quinn]:      https://github.com/quinn-rs/quinn
582//! [pion]:       https://github.com/pion/webrtc
583//! [webrtc-rs]:  https://github.com/webrtc-rs/webrtc
584//! [zulip]:      https://str0m.zulipchat.com/join/hsiuva2zx47ujrwgmucjez5o/
585//! [zulip-anon]: https://str0m.zulipchat.com
586//! [ice]:        https://www.rfc-editor.org/rfc/rfc8445
587//! [lookback]:   https://www.lookback.com
588//! [x-post]:     https://github.com/algesten/str0m/blob/main/examples/http-post.rs
589//! [x-chat]:     https://github.com/algesten/str0m/blob/main/examples/chat.rs
590//! [intg]:       https://github.com/algesten/str0m/blob/main/tests/unidirectional.rs#L12
591//! [ff]:         https://en.wikipedia.org/wiki/Fail-fast
592//! [catch]:      https://doc.rust-lang.org/std/panic/fn.catch_unwind.html
593//! [evmed]:      https://docs.rs/str0m/*/str0m/enum.Event.html#variant.MediaData
594//! [writer]:     https://docs.rs/str0m/*/str0m/media/struct.Writer.html#method.write
595//! [reqkey]:     https://docs.rs/str0m/*/str0m/media/struct.Writer.html#method.request_keyframe
596//! [rtppak]:     https://docs.rs/str0m/*/str0m/enum.Event.html#variant.RtpPacket
597//! [wrtrtp]:     https://docs.rs/str0m/*/str0m/rtp/struct.StreamTx.html#method.write_rtp
598//! [reqkey2]:    https://docs.rs/str0m/*/str0m/rtp/struct.StreamRx.html#method.request_keyframe
599//! [bitwhip]:    https://github.com/bitwhip/bitwhip
600
601#![forbid(unsafe_code)]
602#![allow(clippy::new_without_default)]
603#![allow(clippy::bool_to_int_with_if)]
604#![allow(clippy::assertions_on_constants)]
605#![allow(clippy::manual_range_contains)]
606#![allow(clippy::get_first)]
607#![allow(clippy::needless_lifetimes)]
608#![allow(clippy::precedence)]
609#![allow(clippy::doc_overindented_list_items)]
610#![allow(clippy::uninlined_format_args)]
611#![allow(mismatched_lifetime_syntaxes)]
612#![deny(missing_docs)]
613
614#[macro_use]
615extern crate tracing;
616
617use bwe::{Bwe, BweKind};
618use change::{DirectApi, SdpApi};
619use rtp::RawPacket;
620use std::fmt;
621use std::net::SocketAddr;
622use std::time::{Duration, Instant};
623use streams::RtpPacket;
624use streams::StreamPaused;
625use util::{InstantExt, Pii};
626
627mod crypto;
628use crypto::CryptoProvider;
629use crypto::Fingerprint;
630
631mod dtls;
632use dtls::{Dtls, DtlsCert, DtlsCertOptions, DtlsEvent};
633
634#[path = "ice/mod.rs"]
635mod ice_;
636use ice_::IceAgent;
637use ice_::IceAgentEvent;
638pub use ice_::{Candidate, CandidateKind, IceConnectionState, IceCreds};
639
640/// Additional configuration.
641pub mod config {
642    pub use super::crypto::{CryptoProvider, DtlsCert, DtlsCertOptions, DtlsPKeyType, Fingerprint};
643}
644
645/// Low level ICE access.
646// The ICE API is not necessary to interact with directly for "regular"
647// use of str0m. This is exported for other libraries that want to
648// reuse str0m's ICE implementation. In the future we might turn this
649// into a separate crate.
650#[doc(hidden)]
651pub mod ice {
652    pub use crate::ice_::IceCreds;
653    pub use crate::ice_::{default_local_preference, LocalPreference};
654    pub use crate::ice_::{IceAgent, IceAgentEvent};
655    pub use crate::io::{StunMessage, StunMessageBuilder, StunPacket, TransId};
656}
657
658mod io;
659use io::DatagramRecvInner;
660
661mod packet;
662
663#[path = "rtp/mod.rs"]
664mod rtp_;
665use rtp_::{Bitrate, DataSize};
666use rtp_::{Extension, ExtensionMap};
667
668/// Low level RTP access.
669pub mod rtp {
670    /// Feedback for RTP.
671    pub mod rtcp {
672        pub use crate::rtp_::{Descriptions, ExtendedReport, Fir, Goodbye, Nack, Pli};
673        pub use crate::rtp_::{Dlrr, NackEntry, ReceptionReport, ReportBlock};
674        pub use crate::rtp_::{FirEntry, ReceiverReport, SenderInfo, SenderReport, Twcc};
675        pub use crate::rtp_::{ReportList, Rrtr, Rtcp, Sdes, SdesType};
676    }
677    use self::rtcp::Rtcp;
678
679    /// Video Layers Allocation RTP Header Extension
680    pub mod vla;
681    pub use crate::rtp_::{Extension, ExtensionMap, ExtensionSerializer};
682    pub use crate::rtp_::{ExtensionValues, UserExtensionValues};
683
684    pub use crate::rtp_::{RtpHeader, SeqNo, Ssrc, VideoOrientation};
685    pub use crate::streams::{RtpPacket, StreamPaused, StreamRx, StreamTx};
686
687    /// Debug output of the unencrypted RTP and RTCP packets.
688    ///
689    /// Enable using [`RtcConfig::enable_raw_packets()`][crate::RtcConfig::enable_raw_packets].
690    /// This clones data, and is therefore expensive.
691    /// Should not be enabled outside of tests and troubleshooting.
692    #[derive(Debug)]
693    pub enum RawPacket {
694        /// Sent RTCP.
695        RtcpTx(Rtcp),
696        /// Incoming RTCP.
697        RtcpRx(Rtcp),
698        /// Sent RTP.
699        RtpTx(RtpHeader, Vec<u8>),
700        /// Incoming RTP.
701        RtpRx(RtpHeader, Vec<u8>),
702    }
703}
704
705pub mod bwe;
706
707mod sctp;
708use sctp::{RtcSctp, SctpEvent};
709
710mod sdp;
711
712pub mod format;
713use format::CodecConfig;
714
715pub mod channel;
716use channel::{Channel, ChannelData, ChannelHandler, ChannelId};
717
718pub mod media;
719use media::{Direction, Media, Mid, Pt, Rid, Writer};
720use media::{KeyframeRequest, KeyframeRequestKind};
721use media::{MediaAdded, MediaChanged, MediaData};
722
723pub mod change;
724
725mod util;
726use util::{already_happened, not_happening, Soonest};
727
728mod session;
729use session::Session;
730
731pub mod stats;
732
733use stats::{CandidatePairStats, CandidateStats, MediaEgressStats, MediaIngressStats};
734use stats::{PeerStats, Stats, StatsEvent, StatsSnapshot};
735
736mod streams;
737
738pub mod error;
739
740/// Network related types to get socket data in/out of [`Rtc`].
741pub mod net {
742    pub use crate::io::{DatagramRecv, DatagramSend, Protocol, Receive, Transmit};
743}
744
745const VERSION: &str = env!("CARGO_PKG_VERSION");
746
747pub use error::RtcError;
748
749/// Instance that does WebRTC. Main struct of the entire library.
750///
751/// ## Usage
752///
753/// ```no_run
754/// # use str0m::{Rtc, Output, Input};
755/// let mut rtc = Rtc::new();
756///
757/// loop {
758///     let timeout = match rtc.poll_output().unwrap() {
759///         Output::Timeout(v) => v,
760///         Output::Transmit(t) => {
761///             // TODO: Send data to remote peer.
762///             continue; // poll again
763///         }
764///         Output::Event(e) => {
765///             // TODO: Handle event.
766///             continue; // poll again
767///         }
768///     };
769///
770///     // TODO: Wait for one of two events, reaching `timeout`
771///     //       or receiving network input. Both are encapsulated
772///     //       in the Input enum.
773///     let input: Input = todo!();
774///
775///     rtc.handle_input(input).unwrap();
776/// }
777/// ```
778pub struct Rtc {
779    alive: bool,
780    ice: IceAgent,
781    dtls: Dtls,
782    sctp: RtcSctp,
783    chan: ChannelHandler,
784    stats: Option<Stats>,
785    session: Session,
786    remote_fingerprint: Option<Fingerprint>,
787    remote_addrs: Vec<SocketAddr>,
788    send_addr: Option<SendAddr>,
789    need_init_time: bool,
790    last_now: Instant,
791    peer_bytes_rx: u64,
792    peer_bytes_tx: u64,
793    change_counter: usize,
794    last_timeout_reason: Reason,
795    crypto_provider: CryptoProvider,
796    fingerprint_verification: bool,
797}
798
799struct SendAddr {
800    proto: net::Protocol,
801    source: SocketAddr,
802    destination: SocketAddr,
803}
804
805/// Events produced by [`Rtc::poll_output()`].
806#[derive(Debug)]
807#[non_exhaustive]
808#[rustfmt::skip]
809pub enum Event {
810    // =================== ICE related events ===================
811
812    /// Emitted when we got ICE connection and established DTLS.
813    Connected,
814
815    /// ICE connection state changes tells us whether the [`Rtc`] instance is
816    /// connected to the peer or not.
817    IceConnectionStateChange(IceConnectionState),
818
819    // =================== Media related events ==================
820
821    /// Upon detecting the remote side adding new media to the session.
822    ///
823    /// For locally added media, this event never fires. Thus it can be thought of as an
824    /// "SDP only" event. If the direct API is used on both sides, the declaration is local \
825    /// to both sides and the event never fires.
826    ///
827    /// The [`Media`] instance is available via [`Rtc::media()`].
828    MediaAdded(MediaAdded),
829
830    /// Incoming media data sent by the remote peer.
831    MediaData(MediaData),
832
833    /// Changes to the media may be emitted.
834    ///
835    ///. Currently only covers a change of direction.
836    MediaChanged(MediaChanged),
837
838    // =================== Data channel related events ===================
839
840    /// A data channel has opened.
841    ///
842    /// The string is the channel label which is set by the opening peer and can
843    /// be used to identify the purpose of the channel when there are more than one.
844    ///
845    /// The negotiation is to set up an SCTP association via DTLS. Subsequent data
846    /// channels reuse the same association.
847    ///
848    /// Upon this event, the [`Channel`] can be obtained via [`Rtc::channel()`].
849    ///
850    /// For [`SdpApi`]: The first ever data channel results in an SDP
851    /// negotiation, and this events comes at the end of that.
852    ChannelOpen(ChannelId, String),
853
854    /// Incoming data channel data from the remote peer.
855    ChannelData(ChannelData),
856
857    /// A data channel has been closed.
858    ChannelClose(ChannelId),
859
860    /// A data channel's buffered amount has dropped below the configured threshold.
861    ChannelBufferedAmountLow(ChannelId),
862
863    // =================== Statistics and BWE related events ===================
864
865    /// Statistics event for the Rtc instance
866    ///
867    /// Includes both media traffic (rtp payload) as well as all traffic
868    PeerStats(PeerStats),
869
870    /// Aggregated statistics for each media (mid, rid) in the ingress direction
871    MediaIngressStats(MediaIngressStats),
872
873    /// Aggregated statistics for each media (mid, rid) in the egress direction
874    MediaEgressStats(MediaEgressStats),
875
876    /// A new estimate from the bandwidth estimation subsystem.
877    EgressBitrateEstimate(BweKind),
878
879    // =================== RTP related events ===================
880
881    /// Incoming keyframe request for media that we are sending to the remote peer.
882    ///
883    /// The request is either PLI (Picture Loss Indication) or FIR (Full Intra Request).
884    KeyframeRequest(KeyframeRequest),
885
886    /// Whether an incoming encoded stream is paused.
887    ///
888    /// This means the stream has not received any data for some time (default 1.5 seconds).
889    StreamPaused(StreamPaused),
890
891    /// Incoming RTP data.
892    RtpPacket(RtpPacket),
893
894    /// Debug output of incoming and outgoing RTCP/RTP packets.
895    ///
896    /// Enable using [`RtcConfig::enable_raw_packets()`].
897    /// This clones data, and is therefore expensive.
898    /// Should not be enabled outside of tests and troubleshooting.
899    RawPacket(Box<RawPacket>),
900}
901
902impl Event {
903    /// Reference to the [`RawPacket`] if this is indeed an `Event::RawPacket`.
904    pub fn as_raw_packet(&self) -> Option<&RawPacket> {
905        if let Self::RawPacket(boxed) = &self {
906            Some(&**boxed)
907        } else {
908            None
909        }
910    }
911}
912
913/// Input as expected by [`Rtc::handle_input()`]. Either network data or a timeout.
914#[derive(Debug)]
915#[allow(clippy::large_enum_variant)] // We purposely don't want to allocate.
916pub enum Input<'a> {
917    /// A timeout without any network input.
918    Timeout(Instant),
919    /// Network input.
920    Receive(Instant, net::Receive<'a>),
921}
922
923/// Output produced by [`Rtc::poll_output()`]
924#[allow(clippy::large_enum_variant)]
925#[derive(Debug)]
926pub enum Output {
927    /// When the [`Rtc`] instance expects an [`Input::Timeout`].
928    Timeout(Instant),
929
930    /// Network data that is to be sent.
931    Transmit(net::Transmit),
932
933    /// Some event such as media data arriving from the remote peer or connection events.
934    Event(Event),
935}
936
937/// The reason for the next [`Output::Timeout`].
938#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
939pub enum Reason {
940    /// No timeout scheduled.
941    ///
942    /// The timeout value is in the distant future.
943    NotHappening,
944
945    /// The DTLS subsystem.
946    ///
947    /// Only relevant during handshaking.
948    DTLS,
949
950    /// The ICE agent.
951    ///
952    /// Includes checking candidate pairs and various cleanups.
953    Ice,
954
955    /// The SCTP subsystem.
956    ///
957    /// Things like handling retransmissions and keep-alive checks.
958    Sctp,
959
960    /// Data channels.
961    ///
962    /// Scheduled when we need to open allocations using SCTP.
963    Channel,
964
965    /// Stats gathering (if enabled).
966    ///
967    /// Periodic gathering of statistics.
968    Stats,
969
970    /// Regular RTP feedback.
971    ///
972    /// Receiver reports (RR) and sender reports (SR).
973    Feedback,
974
975    /// Sending of RTP NACK.
976    ///
977    /// When missing packets are discovered, a NACK is scheduled.
978    Nack,
979
980    /// Reporting of TWCC (if enabled).
981    ///
982    /// All incoming RTP packets are reported using TWCC. Enabled via SDP if both
983    /// sides support it.
984    Twcc,
985
986    /// RTP streams not receiving data goes into a paused state.
987    ///
988    /// Whenever an RTP receive stream receives data, a new timeout is scheduled.
989    PauseCheck,
990
991    /// Preprocessing of RTP packets to be sent.
992    ///
993    /// Housekeeping task in RTP send streams.
994    SendStream,
995
996    /// Packetizing of media into RTP data (if used).
997    ///
998    /// Written media data needs packetizing. This is not used in RTP mode.
999    Packetize,
1000
1001    /// Paced sending of RTP packets (if BWE is enabled).
1002    ///
1003    /// The pacer ensures bigger RTP chunks, like keyframes, are not sent as a burst,
1004    /// but sent smoothly.
1005    Pacing,
1006
1007    /// Bandwidth estimation update (if enabled).
1008    ///
1009    /// Calculations regarding sender bandwidth using incoming TWCC.
1010    Bwe,
1011}
1012
1013impl Default for Reason {
1014    fn default() -> Self {
1015        Self::NotHappening
1016    }
1017}
1018
1019impl Rtc {
1020    /// Creates a new instance with default settings.
1021    ///
1022    /// To configure the instance, use [`RtcConfig`].
1023    ///
1024    /// ```
1025    /// # #[cfg(feature = "openssl")] {
1026    /// use str0m::Rtc;
1027    ///
1028    /// let rtc = Rtc::new();
1029    /// # }
1030    /// ```
1031    pub fn new() -> Self {
1032        let config = RtcConfig::default();
1033        Self::new_from_config(config)
1034    }
1035
1036    /// Creates a config builder that configures an [`Rtc`] instance.
1037    ///
1038    /// ```
1039    /// # #[cfg(feature = "openssl")] {
1040    /// # use str0m::Rtc;
1041    /// let rtc = Rtc::builder()
1042    ///     .set_ice_lite(true)
1043    ///     .build();
1044    /// # }
1045    /// ```
1046    pub fn builder() -> RtcConfig {
1047        RtcConfig::new()
1048    }
1049
1050    pub(crate) fn new_from_config(config: RtcConfig) -> Self {
1051        let session = Session::new(&config);
1052
1053        let local_creds = config.local_ice_credentials.unwrap_or_else(IceCreds::new);
1054        let mut ice = IceAgent::with_local_credentials(local_creds);
1055        if config.ice_lite {
1056            ice.set_ice_lite(config.ice_lite);
1057        }
1058
1059        if let Some(initial_stun_rto) = config.initial_stun_rto {
1060            ice.set_initial_stun_rto(initial_stun_rto);
1061        }
1062
1063        if let Some(max_stun_rto) = config.max_stun_rto {
1064            ice.set_max_stun_rto(max_stun_rto);
1065        }
1066
1067        if let Some(max_stun_retransmits) = config.max_stun_retransmits {
1068            ice.set_max_stun_retransmits(max_stun_retransmits);
1069        }
1070
1071        let dtls_cert = match config.dtls_cert_config {
1072            DtlsCertConfig::Options(options) => DtlsCert::new(config.crypto_provider, options),
1073            DtlsCertConfig::PregeneratedCert(cert) => cert,
1074        };
1075
1076        let crypto_provider = dtls_cert.crypto_provider();
1077
1078        Rtc {
1079            alive: true,
1080            ice,
1081            dtls: Dtls::new(dtls_cert).expect("DTLS to init without problem"),
1082            session,
1083            sctp: RtcSctp::new(),
1084            chan: ChannelHandler::default(),
1085            stats: config.stats_interval.map(Stats::new),
1086            remote_fingerprint: None,
1087            remote_addrs: vec![],
1088            send_addr: None,
1089            need_init_time: true,
1090            last_now: already_happened(),
1091            peer_bytes_rx: 0,
1092            peer_bytes_tx: 0,
1093            change_counter: 0,
1094            last_timeout_reason: Reason::NotHappening,
1095            crypto_provider,
1096            fingerprint_verification: config.fingerprint_verification,
1097        }
1098    }
1099
1100    /// Tests if this instance is still working.
1101    ///
1102    /// Certain events will straight away disconnect the `Rtc` instance, such as
1103    /// the DTLS fingerprint from the setup not matching that of the TLS negotiation
1104    /// (since that would potentially indicate a MITM attack!).
1105    ///
1106    /// The instance can be manually disconnected using [`Rtc::disconnect()`].
1107    ///
1108    /// ```
1109    /// # #[cfg(feature = "openssl")] {
1110    /// # use str0m::Rtc;
1111    /// let mut rtc = Rtc::new();
1112    ///
1113    /// assert!(rtc.is_alive());
1114    ///
1115    /// rtc.disconnect();
1116    /// assert!(!rtc.is_alive());
1117    /// # }
1118    /// ```
1119    pub fn is_alive(&self) -> bool {
1120        self.alive
1121    }
1122
1123    /// Force disconnects the instance making [`Rtc::is_alive()`] return `false`.
1124    ///
1125    /// This makes [`Rtc::poll_output`] and [`Rtc::handle_input`] go inert and not
1126    /// produce anymore network output or events.
1127    ///
1128    /// ```
1129    /// # #[cfg(feature = "openssl")] {
1130    /// # use str0m::Rtc;
1131    /// let mut rtc = Rtc::new();
1132    ///
1133    /// rtc.disconnect();
1134    /// assert!(!rtc.is_alive());
1135    /// # }
1136    /// ```
1137    pub fn disconnect(&mut self) {
1138        if self.alive {
1139            debug!("Set alive=false");
1140            self.alive = false;
1141        }
1142    }
1143
1144    /// Add a local ICE candidate. Local candidates are socket addresses the `Rtc` instance
1145    /// use for communicating with the peer.
1146    ///
1147    /// If the candidate is accepted by the `Rtc` instance, it will return `Some` with a reference
1148    /// to it. You should then signal this candidate to the remote peer.
1149    ///
1150    /// This library has no built-in discovery of local network addresses on the host
1151    /// or NATed addresses via a STUN server or TURN server. The user of the library
1152    /// is expected to add new local candidates as they are discovered.
1153    ///
1154    /// In WebRTC lingo, the `Rtc` instance is permanently in a mode of [Trickle Ice][1]. It's
1155    /// however advisable to add at least one local candidate before starting the instance.
1156    ///
1157    /// ```
1158    /// # #[cfg(feature = "openssl")] {
1159    /// # use str0m::{Rtc, Candidate};
1160    /// let mut rtc = Rtc::new();
1161    ///
1162    /// let a = "127.0.0.1:5000".parse().unwrap();
1163    /// let c = Candidate::host(a, "udp").unwrap();
1164    ///
1165    /// rtc.add_local_candidate(c);
1166    /// # }
1167    /// ```
1168    ///
1169    /// [1]: https://www.rfc-editor.org/rfc/rfc8838.txt
1170    pub fn add_local_candidate(&mut self, c: Candidate) -> Option<&Candidate> {
1171        self.ice.add_local_candidate(c)
1172    }
1173
1174    /// Add a remote ICE candidate. Remote candidates are addresses of the peer.
1175    ///
1176    /// For [`SdpApi`]: Remote candidates are typically added via
1177    /// receiving a remote [`SdpOffer`][change::SdpOffer] or [`SdpAnswer`][change::SdpAnswer].
1178    ///
1179    /// However for the case of [Trickle Ice][1], this is the way to add remote candidates
1180    /// that are "trickled" from the other side.
1181    ///
1182    /// ```
1183    /// # #[cfg(feature = "openssl")] {
1184    /// # use str0m::{Rtc, Candidate};
1185    /// let mut rtc = Rtc::new();
1186    ///
1187    /// let a = "1.2.3.4:5000".parse().unwrap();
1188    /// let c = Candidate::host(a, "udp").unwrap();
1189    ///
1190    /// rtc.add_remote_candidate(c);
1191    /// }
1192    /// ```
1193    ///
1194    /// [1]: https://www.rfc-editor.org/rfc/rfc8838.txt
1195    pub fn add_remote_candidate(&mut self, c: Candidate) {
1196        self.ice.add_remote_candidate(c);
1197    }
1198
1199    /// Checks if we are connected.
1200    ///
1201    /// This tests if we have ICE connection, DTLS and the SRTP crypto derived contexts are up.
1202    pub fn is_connected(&self) -> bool {
1203        self.ice.state().is_connected() && self.dtls.is_connected() && self.session.is_connected()
1204    }
1205
1206    /// Make changes to the Rtc session via SDP.
1207    ///
1208    /// ```no_run
1209    /// # use str0m::Rtc;
1210    /// # use str0m::media::{MediaKind, Direction};
1211    /// # use str0m::change::SdpAnswer;
1212    /// let mut rtc = Rtc::new();
1213    ///
1214    /// let mut changes = rtc.sdp_api();
1215    /// let mid_audio = changes.add_media(MediaKind::Audio, Direction::SendOnly, None, None, None);
1216    /// let mid_video = changes.add_media(MediaKind::Video, Direction::SendOnly, None, None, None);
1217    ///
1218    /// let (offer, pending) = changes.apply().unwrap();
1219    /// let json = serde_json::to_vec(&offer).unwrap();
1220    ///
1221    /// // Send json OFFER to remote peer. Receive an answer back.
1222    /// let answer: SdpAnswer = todo!();
1223    ///
1224    /// rtc.sdp_api().accept_answer(pending, answer).unwrap();
1225    /// ```
1226    pub fn sdp_api(&mut self) -> SdpApi {
1227        SdpApi::new(self)
1228    }
1229
1230    /// Makes direct changes to the Rtc session.
1231    ///
1232    /// This is a low level API. For "normal" use via SDP, see [`Rtc::sdp_api()`].
1233    pub fn direct_api(&mut self) -> DirectApi {
1234        DirectApi::new(self)
1235    }
1236
1237    /// Send outgoing media data (samples) or request keyframes.
1238    ///
1239    /// Returns `None` if the direction isn't sending (`sendrecv` or `sendonly`).
1240    ///
1241    /// ```no_run
1242    /// # use str0m::Rtc;
1243    /// # use str0m::media::{MediaData, Mid};
1244    /// # use str0m::format::PayloadParams;
1245    /// let mut rtc = Rtc::new();
1246    ///
1247    /// // add candidates, do SDP negotiation
1248    /// let mid: Mid = todo!(); // obtain mid from Event::MediaAdded.
1249    ///
1250    /// // Writer for this mid.
1251    /// let writer = rtc.writer(mid).unwrap();
1252    ///
1253    /// // Get incoming media data from another peer
1254    /// let data: MediaData = todo!();
1255    ///
1256    /// // Match incoming PT to an outgoing PT.
1257    /// let pt = writer.match_params(data.params).unwrap();
1258    ///
1259    /// writer.write(pt, data.network_time, data.time, data.data).unwrap();
1260    /// ```
1261    ///
1262    /// This is a sample level API: For RTP level see [`DirectApi::stream_tx()`]
1263    /// and [`DirectApi::stream_rx()`].
1264    ///
1265    pub fn writer(&mut self, mid: Mid) -> Option<Writer> {
1266        if self.session.rtp_mode {
1267            panic!("In rtp_mode use direct_api().stream_tx().write_rtp()");
1268        }
1269
1270        // This does not catch potential RIDs required to send simulcast, but
1271        // it's a good start. An error might arise later on RID mismatch.
1272        self.session.media_by_mid_mut(mid)?;
1273
1274        Some(Writer::new(&mut self.session, mid))
1275    }
1276
1277    /// Currently configured media.
1278    ///
1279    /// Read only access. Changes are made via [`Rtc::sdp_api()`] or [`Rtc::direct_api()`].
1280    pub fn media(&self, mid: Mid) -> Option<&Media> {
1281        self.session.media_by_mid(mid)
1282    }
1283
1284    fn init_dtls(&mut self, active: bool) -> Result<(), RtcError> {
1285        if self.dtls.is_inited() {
1286            return Ok(());
1287        }
1288
1289        debug!("DTLS setup is: {:?}", active);
1290        self.dtls.set_active(active);
1291
1292        if active {
1293            self.dtls.handle_handshake()?;
1294        }
1295
1296        Ok(())
1297    }
1298
1299    fn init_sctp(&mut self, client: bool) {
1300        // If we got an m=application line, ensure we have negotiated the
1301        // SCTP association with the other side.
1302        if self.sctp.is_inited() {
1303            return;
1304        }
1305
1306        self.sctp.init(client, self.last_now);
1307    }
1308
1309    /// Creates a new Mid that is not in the session already.
1310    pub(crate) fn new_mid(&self) -> Mid {
1311        loop {
1312            let mid = Mid::new();
1313            if !self.session.has_mid(mid) {
1314                break mid;
1315            }
1316        }
1317    }
1318
1319    /// Poll the `Rtc` instance for output. Output can be three things, something to _Transmit_
1320    /// via a UDP socket (maybe via a TURN server). An _Event_, such as receiving media data,
1321    /// or a _Timeout_.
1322    ///
1323    /// The user of the library is expected to continuously call this function and deal with
1324    /// the output until it encounters an [`Output::Timeout`] at which point no further output
1325    /// is produced (if polled again, it will result in just another timeout).
1326    ///
1327    /// After exhausting the `poll_output`, the function will only produce more output again
1328    /// when one of two things happen:
1329    ///
1330    /// 1. The polled timeout is reached.
1331    /// 2. New network input.
1332    ///
1333    /// See [`Rtc`] instance documentation for how this is expected to be used in a loop.
1334    pub fn poll_output(&mut self) -> Result<Output, RtcError> {
1335        let o = self.do_poll_output()?;
1336
1337        match &o {
1338            Output::Event(e) => match e {
1339                Event::ChannelData(_) | Event::MediaData(_) | Event::RtpPacket(_) => {
1340                    trace!("{:?}", e)
1341                }
1342                _ => debug!("{:?}", e),
1343            },
1344            Output::Transmit(t) => {
1345                self.peer_bytes_tx += t.contents.len() as u64;
1346                trace!("OUT {:?}", t)
1347            }
1348            Output::Timeout(_t) => {}
1349        }
1350
1351        Ok(o)
1352    }
1353
1354    fn do_poll_output(&mut self) -> Result<Output, RtcError> {
1355        if !self.alive {
1356            self.last_timeout_reason = Reason::NotHappening;
1357            return Ok(Output::Timeout(not_happening()));
1358        }
1359
1360        while let Some(e) = self.ice.poll_event() {
1361            match e {
1362                IceAgentEvent::IceRestart(_) => {
1363                    //
1364                }
1365                IceAgentEvent::IceConnectionStateChange(v) => {
1366                    return Ok(Output::Event(Event::IceConnectionStateChange(v)))
1367                }
1368                IceAgentEvent::DiscoveredRecv { proto, source } => {
1369                    debug!("ICE remote address: {:?}/{:?}", Pii(source), proto);
1370                    self.remote_addrs.push(source);
1371                    while self.remote_addrs.len() > 20 {
1372                        self.remote_addrs.remove(0);
1373                    }
1374                }
1375                IceAgentEvent::NominatedSend {
1376                    proto,
1377                    source,
1378                    destination,
1379                } => {
1380                    debug!(
1381                        "ICE nominated send from: {:?} to: {:?} with protocol {:?}",
1382                        Pii(source),
1383                        Pii(destination),
1384                        proto,
1385                    );
1386                    self.send_addr = Some(SendAddr {
1387                        proto,
1388                        source,
1389                        destination,
1390                    });
1391                }
1392            }
1393        }
1394
1395        let mut dtls_connected = false;
1396
1397        while let Some(e) = self.dtls.poll_event() {
1398            match e {
1399                DtlsEvent::Connected => {
1400                    debug!("DTLS connected");
1401                    dtls_connected = true;
1402                }
1403                DtlsEvent::SrtpKeyingMaterial(mat, srtp_profile) => {
1404                    debug!(
1405                        "DTLS set SRTP keying material and profile: {}",
1406                        srtp_profile
1407                    );
1408                    let active = self.dtls.is_active().expect("DTLS must be inited by now");
1409                    let srtp_crypto = self.crypto_provider.srtp_crypto();
1410                    self.session
1411                        .set_keying_material(mat, &srtp_crypto, srtp_profile, active);
1412                }
1413                DtlsEvent::RemoteFingerprint(v1) => {
1414                    debug!("DTLS verify remote fingerprint");
1415                    if let Some(v2) = &self.remote_fingerprint {
1416                        if !self.fingerprint_verification {
1417                            debug!("DTLS fingerprint verification disabled");
1418                        } else if v1 != *v2 {
1419                            self.disconnect();
1420                            return Err(RtcError::RemoteSdp("remote fingerprint no match".into()));
1421                        }
1422                    } else {
1423                        self.disconnect();
1424                        return Err(RtcError::RemoteSdp("no a=fingerprint before dtls".into()));
1425                    }
1426                }
1427                DtlsEvent::Data(v) => {
1428                    self.sctp.handle_input(self.last_now, &v);
1429                }
1430            }
1431        }
1432
1433        if dtls_connected {
1434            return Ok(Output::Event(Event::Connected));
1435        }
1436
1437        while let Some(e) = self.sctp.poll() {
1438            match e {
1439                SctpEvent::Transmit { mut packets } => {
1440                    if let Some(v) = packets.front() {
1441                        if let Err(e) = self.dtls.handle_input(v) {
1442                            if e.is_would_block() {
1443                                self.sctp.push_back_transmit(packets);
1444                                break;
1445                            } else {
1446                                return Err(e.into());
1447                            }
1448                        }
1449                        packets.pop_front();
1450                        // If there are still packets, they are sent on next
1451                        // poll_output()
1452                        if !packets.is_empty() {
1453                            self.sctp.push_back_transmit(packets);
1454                        }
1455                        break;
1456                    }
1457                }
1458                SctpEvent::Open { id, label } => {
1459                    self.chan.ensure_channel_id_for(id);
1460                    let id = self.chan.channel_id_by_stream_id(id).unwrap();
1461                    return Ok(Output::Event(Event::ChannelOpen(id, label)));
1462                }
1463                SctpEvent::Close { id } => {
1464                    let Some(id) = self.chan.channel_id_by_stream_id(id) else {
1465                        warn!("Drop ChannelClose event for id: {:?}", id);
1466                        continue;
1467                    };
1468                    self.chan.remove_channel(id);
1469                    return Ok(Output::Event(Event::ChannelClose(id)));
1470                }
1471                SctpEvent::Data { id, binary, data } => {
1472                    let Some(id) = self.chan.channel_id_by_stream_id(id) else {
1473                        warn!("Drop ChannelData event for id: {:?}", id);
1474                        continue;
1475                    };
1476                    let cd = ChannelData { id, binary, data };
1477                    return Ok(Output::Event(Event::ChannelData(cd)));
1478                }
1479                SctpEvent::BufferedAmountLow { id } => {
1480                    let Some(id) = self.chan.channel_id_by_stream_id(id) else {
1481                        warn!("Drop BufferedAmountLow for id: {:?}", id);
1482                        continue;
1483                    };
1484                    return Ok(Output::Event(Event::ChannelBufferedAmountLow(id)));
1485                }
1486            }
1487        }
1488
1489        if let Some(ev) = self.session.poll_event() {
1490            return Ok(Output::Event(ev));
1491        }
1492
1493        // Some polling needs to bubble up errors.
1494        if let Some(ev) = self.session.poll_event_fallible()? {
1495            return Ok(Output::Event(ev));
1496        }
1497
1498        if let Some(e) = self.stats.as_mut().and_then(|s| s.poll_output()) {
1499            return Ok(match e {
1500                StatsEvent::Peer(s) => Output::Event(Event::PeerStats(s)),
1501                StatsEvent::MediaIngress(s) => Output::Event(Event::MediaIngressStats(s)),
1502                StatsEvent::MediaEgress(s) => Output::Event(Event::MediaEgressStats(s)),
1503            });
1504        }
1505
1506        if let Some(v) = self.ice.poll_transmit() {
1507            return Ok(Output::Transmit(v));
1508        }
1509
1510        if let Some(send) = &self.send_addr {
1511            // These can only be sent after we got an ICE connection.
1512            let datagram = None
1513                .or_else(|| self.dtls.poll_datagram())
1514                .or_else(|| self.session.poll_datagram(self.last_now));
1515
1516            if let Some(contents) = datagram {
1517                let t = net::Transmit {
1518                    proto: send.proto,
1519                    source: send.source,
1520                    destination: send.destination,
1521                    contents,
1522                };
1523                return Ok(Output::Transmit(t));
1524            }
1525        } else {
1526            // Don't allow accumulated feedback to build up indefinitely
1527            self.session.clear_feedback();
1528        }
1529
1530        let stats = self.stats.as_mut();
1531
1532        let time_and_reason = (None, Reason::NotHappening)
1533            .soonest((self.dtls.poll_timeout(self.last_now), Reason::DTLS))
1534            .soonest((self.ice.poll_timeout(), Reason::Ice))
1535            .soonest(self.session.poll_timeout())
1536            .soonest((self.sctp.poll_timeout(), Reason::Sctp))
1537            .soonest((self.chan.poll_timeout(&self.sctp), Reason::Channel))
1538            .soonest((stats.and_then(|s| s.poll_timeout()), Reason::Stats));
1539
1540        // trace!("poll_output timeout reason: {}", time_and_reason.1);
1541
1542        let time = time_and_reason.0.unwrap_or_else(not_happening);
1543        let reason = time_and_reason.1;
1544
1545        // We want to guarantee time doesn't go backwards.
1546        let next = if time < self.last_now {
1547            self.last_now
1548        } else {
1549            time
1550        };
1551
1552        self.last_timeout_reason = reason;
1553
1554        Ok(Output::Timeout(next))
1555    }
1556
1557    /// The reason for the last [`Output::Timeout`]
1558    ///
1559    /// This is updated when calling [`Rtc::poll_output()`] and the next output
1560    /// is a timeout.
1561    ///
1562    /// ```
1563    /// # #[cfg(feature = "openssl")] {
1564    /// # use str0m::{Rtc, Input, Output, Reason};
1565    /// let mut rtc = Rtc::new();
1566    ///
1567    /// let output = rtc.poll_output().unwrap();
1568    ///
1569    /// // Reason updates every time we get an Output::Timeout
1570    /// assert!(matches!(output, Output::Timeout(_)));
1571    ///
1572    /// // If there are no timeouts scheduled, we get NotHappening. The timeout
1573    /// // value itself will be in the distant future.
1574    /// assert_eq!(rtc.last_timeout_reason(), Reason::DTLS);
1575    /// # }
1576    /// ```
1577    pub fn last_timeout_reason(&self) -> Reason {
1578        self.last_timeout_reason
1579    }
1580
1581    /// Check if this `Rtc` instance accepts the given input. This is used for demultiplexing
1582    /// several `Rtc` instances over the same UDP server socket.
1583    ///
1584    /// [`Input::Timeout`] is always accepted. [`Input::Receive`] is tested against the nominated
1585    /// ICE candidate. If that doesn't match and the incoming data is a STUN packet, the accept call
1586    /// is delegated to the ICE agent which recognizes the remote peer from `a=ufrag`/`a=password`
1587    /// credentials negotiated in the SDP. If that also doesn't match, all remote ICE candidates are
1588    /// checked for a match.
1589    ///
1590    /// In a server setup, the server would try to find an `Rtc` instances using [`Rtc::accepts()`].
1591    /// The first found instance would be given the input via [`Rtc::handle_input()`].
1592    ///
1593    /// ```no_run
1594    /// # use str0m::{Rtc, Input};
1595    /// // A vec holding the managed rtc instances. One instance per remote peer.
1596    /// let mut rtcs = vec![Rtc::new(), Rtc::new(), Rtc::new()];
1597    ///
1598    /// // Configure instances with local ice candidates etc.
1599    ///
1600    /// loop {
1601    ///     // TODO poll_timeout() and handle the output.
1602    ///
1603    ///     let input: Input = todo!(); // read network data from socket.
1604    ///     for rtc in &mut rtcs {
1605    ///         if rtc.accepts(&input) {
1606    ///             rtc.handle_input(input).unwrap();
1607    ///         }
1608    ///     }
1609    /// }
1610    /// ```
1611    pub fn accepts(&self, input: &Input) -> bool {
1612        let Input::Receive(_, r) = input else {
1613            // always accept the Input::Timeout.
1614            return true;
1615        };
1616
1617        // Fast path: DTLS, RTP, and RTCP traffic coming in from the same socket address
1618        // we've nominated for sending via the ICE agent. This is the typical case
1619        if let Some(send_addr) = &self.send_addr {
1620            if r.source == send_addr.destination {
1621                return true;
1622            }
1623        }
1624
1625        // STUN can use the ufrag/password to identify that a message belongs
1626        // to this Rtc instance.
1627        if let DatagramRecvInner::Stun(v) = &r.contents.inner {
1628            return self.ice.accepts_message(v);
1629        }
1630
1631        // Slow path: Occasionally, traffic comes in on a socket address corresponding
1632        // to a successful candidate pair other than the one we've currently nominated.
1633        // This typically happens at the beginning of the connection
1634        if self.ice.has_viable_remote_candidate(r.source) {
1635            return true;
1636        }
1637
1638        false
1639    }
1640
1641    /// Provide input to this `Rtc` instance. Input is either a [`Input::Timeout`] for some
1642    /// time that was previously obtained from [`Rtc::poll_output()`], or [`Input::Receive`]
1643    /// for network data.
1644    ///
1645    /// Both the timeout and the network data contains a [`std::time::Instant`] which drives
1646    /// time forward in the instance. For network data, the intention is to record the time
1647    /// of receiving the network data as precise as possible. This time is used to calculate
1648    /// things like jitter and bandwidth.
1649    ///
1650    /// It's always okay to call [`Rtc::handle_input()`] with a timeout, also before the
1651    /// time obtained via [`Rtc::poll_output()`].
1652    ///
1653    /// ```no_run
1654    /// # use str0m::{Rtc, Input};
1655    /// # use std::time::Instant;
1656    /// let mut rtc = Rtc::new();
1657    ///
1658    /// loop {
1659    ///     let timeout: Instant = todo!(); // rtc.poll_output() until we get a timeout.
1660    ///
1661    ///     let input: Input = todo!(); // wait for network data or timeout.
1662    ///     rtc.handle_input(input);
1663    /// }
1664    /// ```
1665    pub fn handle_input(&mut self, input: Input) -> Result<(), RtcError> {
1666        if !self.alive {
1667            return Ok(());
1668        }
1669
1670        match input {
1671            Input::Timeout(now) => self.do_handle_timeout(now)?,
1672            Input::Receive(now, r) => {
1673                self.do_handle_receive(now, r)?;
1674                self.do_handle_timeout(now)?;
1675            }
1676        }
1677        Ok(())
1678    }
1679
1680    fn init_time(&mut self, now: Instant) {
1681        // The operation is somewhat expensive, hence we only do it once.
1682        if !self.need_init_time {
1683            return;
1684        }
1685
1686        // We assume this first "now" is a time 0 start point for calculating ntp/unix time offsets.
1687        // This initializes the conversion of Instant -> NTP/Unix time.
1688        let _ = now.to_unix_duration();
1689
1690        self.need_init_time = false;
1691    }
1692
1693    fn do_handle_timeout(&mut self, now: Instant) -> Result<(), RtcError> {
1694        self.init_time(now);
1695
1696        self.last_now = now;
1697        self.ice.handle_timeout(now);
1698        self.sctp.handle_timeout(now);
1699        self.chan.handle_timeout(now, &mut self.sctp);
1700        self.session.handle_timeout(now)?;
1701
1702        if let Some(stats) = &mut self.stats {
1703            if stats.wants_timeout(now) {
1704                let mut snapshot = StatsSnapshot::new(now);
1705                snapshot.peer_rx = self.peer_bytes_rx;
1706                snapshot.peer_tx = self.peer_bytes_tx;
1707                snapshot.selected_candidate_pair =
1708                    self.send_addr.as_ref().map(|s| CandidatePairStats {
1709                        protocol: s.proto,
1710                        local: CandidateStats { addr: s.source },
1711                        remote: CandidateStats {
1712                            addr: s.destination,
1713                        },
1714                    });
1715                self.session.visit_stats(now, &mut snapshot);
1716                stats.do_handle_timeout(&mut snapshot);
1717            }
1718        }
1719
1720        Ok(())
1721    }
1722
1723    fn do_handle_receive(&mut self, now: Instant, r: net::Receive) -> Result<(), RtcError> {
1724        self.init_time(now);
1725
1726        trace!("IN {:?}", r);
1727        self.last_now = now;
1728        use DatagramRecvInner::*;
1729
1730        let bytes_rx = match r.contents.inner {
1731            // TODO: stun is already parsed (depacketized) here
1732            Stun(_) => 0,
1733            Dtls(v) | Rtp(v) | Rtcp(v) => v.len(),
1734        };
1735
1736        self.peer_bytes_rx += bytes_rx as u64;
1737
1738        match r.contents.inner {
1739            Stun(stun) => {
1740                let packet = io::StunPacket {
1741                    proto: r.proto,
1742                    source: r.source,
1743                    destination: r.destination,
1744                    message: stun,
1745                };
1746                self.ice.handle_packet(now, packet);
1747            }
1748            Dtls(dtls) => self.dtls.handle_receive(dtls)?,
1749            Rtp(rtp) => self.session.handle_rtp_receive(now, rtp),
1750            Rtcp(rtcp) => self.session.handle_rtcp_receive(now, rtcp),
1751        }
1752
1753        Ok(())
1754    }
1755
1756    /// Obtain handle for writing to a data channel.
1757    ///
1758    /// This is first available when a [`ChannelId`] is advertised via [`Event::ChannelOpen`].
1759    /// The function returns `None` also for IDs from [`SdpApi::add_channel()`].
1760    ///
1761    /// Incoming channel data is via the [`Event::ChannelData`] event.
1762    ///
1763    /// ```no_run
1764    /// # use str0m::{Rtc, channel::ChannelId};
1765    /// let mut rtc = Rtc::new();
1766    ///
1767    /// let cid: ChannelId = todo!(); // obtain channel id from Event::ChannelOpen
1768    /// let channel = rtc.channel(cid).unwrap();
1769    /// // TODO write data channel data.
1770    /// ```
1771    pub fn channel(&mut self, id: ChannelId) -> Option<Channel<'_>> {
1772        if !self.alive {
1773            return None;
1774        }
1775
1776        let sctp_stream_id = self.chan.stream_id_by_channel_id(id)?;
1777
1778        if !self.sctp.is_open(sctp_stream_id) {
1779            return None;
1780        }
1781
1782        Some(Channel::new(sctp_stream_id, self))
1783    }
1784
1785    /// Configure the Bandwidth Estimate (BWE) subsystem.
1786    ///
1787    /// Only relevant if BWE was enabled in the [`RtcConfig::enable_bwe()`]
1788    pub fn bwe(&mut self) -> Bwe {
1789        Bwe(self)
1790    }
1791
1792    fn is_correct_change_id(&self, change_id: usize) -> bool {
1793        self.change_counter == change_id + 1
1794    }
1795
1796    fn next_change_id(&mut self) -> usize {
1797        let n = self.change_counter;
1798        self.change_counter += 1;
1799        n
1800    }
1801
1802    /// The codec configs for sending/receiving data.
1803    ///
1804    /// The configurations can be set with [`RtcConfig`] before setting up the session, and they
1805    /// might be further updated by SDP negotiation.
1806    pub fn codec_config(&self) -> &CodecConfig {
1807        &self.session.codec_config
1808    }
1809}
1810
1811/// Configuation for the DTLS certificate used for the Rtc instance. This can be set to
1812/// allow a pregenerated certificate, or options to pass when generating a certificate
1813/// on-the-fly.
1814///
1815/// The default value is DtlsCertConfig::Options(DtlsCertOptions::default())
1816#[derive(Clone, Debug)]
1817pub enum DtlsCertConfig {
1818    /// The options to use for the DTLS certificate generated for this Rtc instance.
1819    Options(DtlsCertOptions),
1820    /// A pregenerated certificate to use for this Rtc instance.
1821    PregeneratedCert(DtlsCert),
1822}
1823
1824impl Default for DtlsCertConfig {
1825    fn default() -> Self {
1826        DtlsCertConfig::Options(DtlsCertOptions::default())
1827    }
1828}
1829
1830/// Customized config for creating an [`Rtc`] instance.
1831///
1832/// ```
1833/// # #[cfg(feature = "openssl")] {
1834/// use str0m::RtcConfig;
1835///
1836/// let rtc = RtcConfig::new()
1837///     .set_ice_lite(true)
1838///     .build();
1839/// # }
1840/// ```
1841///
1842/// Configs implement [`Clone`] to help create multiple `Rtc` instances.
1843#[derive(Debug, Clone)]
1844pub struct RtcConfig {
1845    local_ice_credentials: Option<IceCreds>,
1846    crypto_provider: CryptoProvider,
1847    dtls_cert_config: DtlsCertConfig,
1848    fingerprint_verification: bool,
1849    ice_lite: bool,
1850    initial_stun_rto: Option<Duration>,
1851    max_stun_rto: Option<Duration>,
1852    max_stun_retransmits: Option<usize>,
1853    codec_config: CodecConfig,
1854    exts: ExtensionMap,
1855    stats_interval: Option<Duration>,
1856    /// Whether to use Bandwidth Estimation to discover the egress bandwidth.
1857    bwe_config: Option<BweConfig>,
1858    reordering_size_audio: usize,
1859    reordering_size_video: usize,
1860    send_buffer_audio: usize,
1861    send_buffer_video: usize,
1862    rtp_mode: bool,
1863    enable_raw_packets: bool,
1864}
1865
1866#[derive(Debug, Clone)]
1867struct BweConfig {
1868    initial_bitrate: Bitrate,
1869    enable_loss_controller: bool,
1870}
1871
1872impl RtcConfig {
1873    /// Creates a new default config.
1874    pub fn new() -> Self {
1875        RtcConfig::default()
1876    }
1877
1878    /// Get the local ICE credentials, if set.
1879    ///
1880    /// If not specified, local credentials will be randomly generated when
1881    /// building the [`Rtc`] instance.
1882    pub fn local_ice_credentials(&self) -> &Option<IceCreds> {
1883        &self.local_ice_credentials
1884    }
1885
1886    /// Explicitly sets local ICE credentials.
1887    pub fn set_local_ice_credentials(mut self, local_ice_credentials: IceCreds) -> Self {
1888        self.local_ice_credentials = Some(local_ice_credentials);
1889        self
1890    }
1891
1892    /// Set the crypto provider.
1893    ///
1894    /// This happens implicitly if you use [`RtcConfig::set_dtls_cert_config()`].
1895    ///
1896    /// Panics: If you `set_dtls_cert_config()` followed by a different [`CryptoProvider`].
1897    ///
1898    /// This overrides what is set in [`CryptoProvider::install_process_default()`].
1899    pub fn set_crypto_provider(mut self, p: CryptoProvider) -> Self {
1900        if let DtlsCertConfig::PregeneratedCert(c) = &self.dtls_cert_config {
1901            if p != c.crypto_provider() {
1902                panic!("set_dtls_cert_config() locked crypto provider to: {}", p);
1903            }
1904        } else {
1905            self.crypto_provider = p;
1906        }
1907        self
1908    }
1909
1910    /// The configured crypto provider.
1911    ///
1912    /// Defaults to what's set in [`CryptoProvider::install_process_default()`] followed
1913    /// by a fallback to [`CryptoProvider::OpenSsl`].
1914    pub fn crypto_provider(&self) -> CryptoProvider {
1915        self.crypto_provider
1916    }
1917
1918    /// Returns the configured DTLS certificate configuration.
1919    ///
1920    /// Defaults to a configuration similar to libwebrtc:
1921    /// ```
1922    /// # use str0m::DtlsCertConfig;
1923    /// # use str0m::config::{DtlsCertOptions, DtlsPKeyType};
1924    ///
1925    /// DtlsCertConfig::Options(DtlsCertOptions {
1926    ///     common_name: "WebRTC".into(),
1927    ///     pkey_type: DtlsPKeyType::EcDsaP256,
1928    /// });
1929    /// ```
1930    pub fn dtls_cert_config(&self) -> &DtlsCertConfig {
1931        &self.dtls_cert_config
1932    }
1933
1934    /// Set the DTLS certificate configuration for certificate generation.
1935    ///
1936    /// Setting this permits you to assign a Pregenerated certificate, or
1937    /// options for certificate generation, such as signing key type, and
1938    /// subject name.
1939    ///
1940    /// If a Pregenerated certificate is set, this locks the `crypto_provider()`
1941    /// setting to the [`CryptoProvider`], for the DTLS certificate.
1942    ///
1943    /// ```
1944    /// # use str0m::{DtlsCertConfig, RtcConfig};
1945    /// # use str0m::config::{DtlsCertOptions, DtlsPKeyType};
1946    ///
1947    /// let dtls_cert_config = DtlsCertConfig::Options(DtlsCertOptions {
1948    ///     common_name: "Clark Kent".into(),
1949    ///     pkey_type: DtlsPKeyType::EcDsaP256,
1950    /// });
1951    ///
1952    /// let rtc_config = RtcConfig::default()
1953    ///     .set_dtls_cert_config(dtls_cert_config);
1954    /// ```
1955    pub fn set_dtls_cert_config(mut self, dtls_cert_config: DtlsCertConfig) -> Self {
1956        if let DtlsCertConfig::PregeneratedCert(ref cert) = dtls_cert_config {
1957            self.crypto_provider = cert.crypto_provider();
1958        }
1959        self.dtls_cert_config = dtls_cert_config;
1960        self
1961    }
1962
1963    /// Toggle ice lite. Ice lite is a mode for WebRTC servers with public IP address.
1964    /// An [`Rtc`] instance in ice lite mode will not make STUN binding requests, but only
1965    /// answer to requests from the remote peer.
1966    ///
1967    /// See [ICE RFC][1]
1968    ///
1969    /// [1]: https://www.rfc-editor.org/rfc/rfc8445#page-13
1970    pub fn set_ice_lite(mut self, enabled: bool) -> Self {
1971        self.ice_lite = enabled;
1972        self
1973    }
1974
1975    /// Sets the initial STUN retransmission timeout (RTO).
1976    ///
1977    /// This is the initial wait time before a STUN request is retransmitted.
1978    /// The timeout will double with each retry, starting from this value.
1979    ///
1980    /// Defaults to 250ms.
1981    pub fn set_initial_stun_rto(&mut self, rto: Duration) {
1982        self.initial_stun_rto = Some(rto);
1983    }
1984
1985    /// Sets the maximum STUN retransmission timeout for the ICE agent.
1986    ///
1987    /// This is the upper bound for how long to wait between retransmissions.
1988    /// It also controls how often successful bindings are checked.
1989    ///
1990    /// Defaults to 3000ms.
1991    pub fn set_max_stun_rto(&mut self, rto: Duration) {
1992        self.max_stun_rto = Some(rto);
1993    }
1994
1995    /// Sets the maximum number of retransmits for STUN messages.
1996    ///
1997    /// Defaults to 9.
1998    pub fn set_max_stun_retransmits(&mut self, num: usize) {
1999        self.max_stun_retransmits = Some(num);
2000    }
2001
2002    /// Get fingerprint verification mode.
2003    ///
2004    /// ```
2005    /// # use str0m::Rtc;
2006    /// let config = Rtc::builder();
2007    ///
2008    /// // Defaults to true.
2009    /// assert!(config.fingerprint_verification());
2010    /// ```
2011    pub fn fingerprint_verification(&self) -> bool {
2012        self.fingerprint_verification
2013    }
2014
2015    /// Toggle certificate fingerprint verification.
2016    ///
2017    /// By default the certificate fingerprint is verified.
2018    pub fn set_fingerprint_verification(mut self, enabled: bool) -> Self {
2019        self.fingerprint_verification = enabled;
2020        self
2021    }
2022
2023    /// Tells whether ice lite is enabled.
2024    ///
2025    /// ```
2026    /// # #[cfg(feature = "openssl")] {
2027    /// # use str0m::Rtc;
2028    /// let config = Rtc::builder();
2029    ///
2030    /// // Defaults to false.
2031    /// assert_eq!(config.ice_lite(), false);
2032    /// # }
2033    /// ```
2034    pub fn ice_lite(&self) -> bool {
2035        self.ice_lite
2036    }
2037
2038    /// Lower level access to precise configuration of codecs (payload types).
2039    pub fn codec_config(&mut self) -> &mut CodecConfig {
2040        &mut self.codec_config
2041    }
2042
2043    /// Clear all configured codecs.
2044    ///
2045    /// ```
2046    /// # #[cfg(feature = "openssl")] {
2047    /// # use str0m::RtcConfig;
2048    /// // For the session to use only OPUS and VP8.
2049    /// let mut rtc = RtcConfig::default()
2050    ///     .clear_codecs()
2051    ///     .enable_opus(true)
2052    ///     .enable_vp8(true)
2053    ///     .build();
2054    /// # }
2055    /// ```
2056    pub fn clear_codecs(mut self) -> Self {
2057        self.codec_config.clear();
2058        self
2059    }
2060
2061    /// Enable opus audio codec.
2062    ///
2063    /// Enabled by default.
2064    pub fn enable_opus(mut self, enabled: bool) -> Self {
2065        self.codec_config.enable_opus(enabled);
2066        self
2067    }
2068
2069    /// Enable PCM μ-law audio codec.
2070    ///
2071    /// This is 14-bit audio compressed to 8-bit as specified by G.711
2072    pub fn enable_pcmu(mut self, enabled: bool) -> Self {
2073        self.codec_config.enable_pcmu(enabled);
2074        self
2075    }
2076
2077    /// Enable PCM a-law audio codec.
2078    ///
2079    /// This is 13-bit audio compressed to 8-bit as specified by G.711
2080    pub fn enable_pcma(mut self, enabled: bool) -> Self {
2081        self.codec_config.enable_pcma(enabled);
2082        self
2083    }
2084
2085    /// Enable VP8 video codec.
2086    ///
2087    /// Enabled by default.
2088    pub fn enable_vp8(mut self, enabled: bool) -> Self {
2089        self.codec_config.enable_vp8(enabled);
2090        self
2091    }
2092
2093    /// Enable H264 video codec.
2094    ///
2095    /// Enabled by default.
2096    pub fn enable_h264(mut self, enabled: bool) -> Self {
2097        self.codec_config.enable_h264(enabled);
2098        self
2099    }
2100
2101    // TODO: AV1 depacketizer/packetizer.
2102    //
2103    // /// Enable AV1 video codec.
2104    // ///
2105    // /// Enabled by default.
2106    // pub fn enable_av1(mut self) -> Self {
2107    //     self.codec_config.add_default_av1();
2108    //     self
2109    // }
2110
2111    /// Enable VP9 video codec.
2112    ///
2113    /// Enabled by default.
2114    pub fn enable_vp9(mut self, enabled: bool) -> Self {
2115        self.codec_config.enable_vp9(enabled);
2116        self
2117    }
2118
2119    /// Configure the RTP extension mappings.
2120    ///
2121    /// The default extension map is
2122    ///
2123    /// ```
2124    /// # use str0m::rtp::{Extension, ExtensionMap};
2125    /// let exts = ExtensionMap::standard();
2126    ///
2127    /// assert_eq!(exts.id_of(Extension::AudioLevel), Some(1));
2128    /// assert_eq!(exts.id_of(Extension::AbsoluteSendTime), Some(2));
2129    /// assert_eq!(exts.id_of(Extension::TransportSequenceNumber), Some(3));
2130    /// assert_eq!(exts.id_of(Extension::RtpMid), Some(4));
2131    /// assert_eq!(exts.id_of(Extension::RtpStreamId), Some(10));
2132    /// assert_eq!(exts.id_of(Extension::RepairedRtpStreamId), Some(11));
2133    /// assert_eq!(exts.id_of(Extension::VideoOrientation), Some(13));
2134    /// ```
2135    pub fn extension_map(&mut self) -> &mut ExtensionMap {
2136        &mut self.exts
2137    }
2138
2139    /// Set the extension map replacing the existing.
2140    pub fn set_extension_map(mut self, exts: ExtensionMap) -> Self {
2141        self.exts = exts;
2142        self
2143    }
2144
2145    /// Clear out the standard extension mappings.
2146    pub fn clear_extension_map(mut self) -> Self {
2147        self.exts.clear();
2148
2149        self
2150    }
2151
2152    /// Set an extension mapping on session level.
2153    ///
2154    /// The media level will be capped by the extension enabled on session level.
2155    ///
2156    /// The id must be 1-14 inclusive (1-indexed).
2157    pub fn set_extension(mut self, id: u8, ext: Extension) -> Self {
2158        self.exts.set(id, ext);
2159        self
2160    }
2161
2162    /// Set the interval between statistics events.
2163    ///
2164    /// None turns off the stats events.
2165    ///
2166    /// This includes [`MediaEgressStats`], [`MediaIngressStats`], [`MediaEgressStats`]
2167    pub fn set_stats_interval(mut self, interval: Option<Duration>) -> Self {
2168        self.stats_interval = interval;
2169        self
2170    }
2171
2172    /// The configured statistics interval.
2173    ///
2174    /// None means statistics are disabled.
2175    ///
2176    /// ```
2177    /// # use str0m::Rtc;
2178    /// # use std::time::Duration;
2179    /// let config = Rtc::builder();
2180    ///
2181    /// // Defaults to None.
2182    /// assert_eq!(config.stats_interval(), None);
2183    /// ```
2184    pub fn stats_interval(&self) -> Option<Duration> {
2185        self.stats_interval
2186    }
2187
2188    /// Enables estimation of available bandwidth (BWE).
2189    ///
2190    /// None disables the BWE. This is an estimation of the send bandwidth, not receive.
2191    ///
2192    /// This includes setting the initial estimate to start with.
2193    pub fn enable_bwe(mut self, initial_estimate: Option<Bitrate>) -> Self {
2194        match initial_estimate {
2195            Some(b) => {
2196                let conf = self.bwe_config.get_or_insert(BweConfig::new(b));
2197                conf.initial_bitrate = b;
2198            }
2199            None => {
2200                self.bwe_config = None;
2201            }
2202        }
2203
2204        self
2205    }
2206
2207    /// Enable the experimental loss based BWE subsystem.
2208    /// Defaults to disabled for now, will be enabled by default in the future.
2209    pub fn enable_experimental_loss_based_bwe(mut self, enabled: bool) -> Self {
2210        if let Some(c) = &mut self.bwe_config {
2211            c.enable_loss_controller = enabled;
2212        }
2213
2214        self
2215    }
2216
2217    /// The initial bitrate as set by [`Self::enable_bwe()`].
2218    ///
2219    /// ```
2220    /// # use str0m::Rtc;
2221    /// let config = Rtc::builder();
2222    ///
2223    /// // Defaults to None - BWE off.
2224    /// assert_eq!(config.bwe_initial_bitrate(), None);
2225    /// ```
2226    pub fn bwe_initial_bitrate(&self) -> Option<Bitrate> {
2227        self.bwe_config.as_ref().map(|c| c.initial_bitrate)
2228    }
2229
2230    /// Sets the number of packets held back for reordering audio packets.
2231    ///
2232    /// Str0m tries to deliver the samples in order. This number determines how many
2233    /// packets to "wait" before releasing media
2234    /// [`contiguous: false`][crate::media::MediaData::contiguous].
2235    ///
2236    /// This setting is ignored in [RTP mode][`RtcConfig::set_rtp_mode()`] where RTP
2237    /// packets can arrive out of order.
2238    pub fn set_reordering_size_audio(mut self, size: usize) -> Self {
2239        self.reordering_size_audio = size;
2240
2241        self
2242    }
2243
2244    /// Returns the setting for audio reordering size.
2245    ///
2246    /// ```
2247    /// # use str0m::Rtc;
2248    /// let config = Rtc::builder();
2249    ///
2250    /// // Defaults to 15.
2251    /// assert_eq!(config.reordering_size_audio(), 15);
2252    /// ```
2253    ///
2254    /// This setting is ignored in [RTP mode][`RtcConfig::set_rtp_mode()`] where RTP
2255    /// packets can arrive out of order.
2256    pub fn reordering_size_audio(&self) -> usize {
2257        self.reordering_size_audio
2258    }
2259
2260    /// Sets the number of packets held back for reordering video packets.
2261    ///
2262    /// Str0m tries to deliver the samples in order. This number determines how many
2263    /// packets to "wait" before releasing media with gaps.
2264    ///
2265    /// This must be at least as big as the number of packets the biggest keyframe can be split over.
2266    ///
2267    /// WARNING: video is very different to audio. Setting this value too low will result in
2268    /// missing video data. The 0 (as described for audio) is not relevant for video.
2269    ///
2270    /// Default: 30
2271    ///
2272    /// This setting is ignored in [RTP mode][`RtcConfig::set_rtp_mode()`] where RTP
2273    /// packets can arrive out of order.
2274    pub fn set_reordering_size_video(mut self, size: usize) -> Self {
2275        self.reordering_size_video = size;
2276
2277        self
2278    }
2279
2280    /// Returns the setting for video reordering size.
2281    ///
2282    /// ```
2283    /// # use str0m::Rtc;
2284    /// let config = Rtc::builder();
2285    ///
2286    /// // Defaults to 30.
2287    /// assert_eq!(config.reordering_size_video(), 30);
2288    /// ```
2289    ///
2290    /// This setting is ignored in [RTP mode][`RtcConfig::set_rtp_mode()`] where RTP
2291    /// packets can arrive out of order.
2292    pub fn reordering_size_video(&self) -> usize {
2293        self.reordering_size_video
2294    }
2295
2296    /// Sets the buffer size for outgoing audio packets.
2297    ///
2298    /// This must be larger than 0. The value configures an internal ring buffer used as a temporary
2299    /// holding space between calling [`Writer::write`][crate::media::Writer::write()] and
2300    /// [`Rtc::poll_output`].
2301    ///
2302    /// For audio one call to `write()` typically results in one RTP packet since the entire payload
2303    /// fits in one. If you can guarantee that every `write()` is a single RTP packet, and is always
2304    /// followed by a `poll_output()`, it might be possible to set this value to 1. But that would give
2305    /// no margins for unexpected patterns.
2306    ///
2307    /// panics if set to 0.
2308    pub fn set_send_buffer_audio(mut self, size: usize) -> Self {
2309        assert!(size > 0);
2310        self.send_buffer_audio = size;
2311        self
2312    }
2313
2314    /// Returns the setting for audio resend size.
2315    ///
2316    /// ```
2317    /// # use str0m::Rtc;
2318    /// let config = Rtc::builder();
2319    ///
2320    /// // Defaults to 50.
2321    /// assert_eq!(config.send_buffer_audio(), 50);
2322    /// ```
2323    pub fn send_buffer_audio(&self) -> usize {
2324        self.send_buffer_audio
2325    }
2326
2327    /// Sets the buffer size for outgoing video packets and resends.
2328    ///
2329    /// This must be larger than 0. The value configures an internal ring buffer that is both
2330    /// used as a temporary holding space between calling [`Writer::write`][crate::media::Writer::write()]
2331    /// and [`Rtc::poll_output`] as well as for fulfilling resends.
2332    ///
2333    /// For video, this buffer is used for more than for audio. First, a call to `write()` often
2334    /// results in multiple RTP packets since large frames don't fit in one payload. That means the buffer
2335    /// must be at least as large to hold all those packets. Second, when the remote requests resends (NACK),
2336    /// those are fulfilled from this buffer. Third, for Bandwidth Estimation (BWE), when probing for
2337    /// available bandwidth, packets from this buffer are used to do "spurious resends", i.e. we do resends
2338    /// for packets that were not asked for.
2339    pub fn set_send_buffer_video(mut self, size: usize) -> Self {
2340        self.send_buffer_video = size;
2341        self
2342    }
2343
2344    /// Returns the setting for video resend size.
2345    ///
2346    /// ```
2347    /// # use str0m::Rtc;
2348    /// let config = Rtc::builder();
2349    ///
2350    /// // Defaults to 1000.
2351    /// assert_eq!(config.send_buffer_video(), 1000);
2352    /// ```
2353    pub fn send_buffer_video(&self) -> usize {
2354        self.send_buffer_video
2355    }
2356
2357    /// Make the entire Rtc be in RTP mode.
2358    ///
2359    /// This means all media, read from [`RtpPacket`] and written to
2360    /// [`StreamTx::write_rtp`][crate::rtp::StreamTx::write_rtp] are RTP packetized.
2361    /// It bypasses all internal packetization/depacketization inside str0m.
2362    ///
2363    /// WARNING: This is a low level API and is not str0m's primary use case.
2364    pub fn set_rtp_mode(mut self, enabled: bool) -> Self {
2365        self.rtp_mode = enabled;
2366
2367        self
2368    }
2369
2370    /// Checks if RTP mode is set.
2371    ///
2372    /// ```
2373    /// # use str0m::Rtc;
2374    /// let config = Rtc::builder();
2375    ///
2376    /// // Defaults to false.
2377    /// assert_eq!(config.rtp_mode(), false);
2378    /// ```
2379    pub fn rtp_mode(&self) -> bool {
2380        self.rtp_mode
2381    }
2382
2383    /// Enable the [`Event::RawPacket`] event.
2384    ///
2385    /// This clones data, and is therefore expensive.
2386    /// Should not be enabled outside of tests and troubleshooting.
2387    pub fn enable_raw_packets(mut self, enabled: bool) -> Self {
2388        self.enable_raw_packets = enabled;
2389        self
2390    }
2391
2392    /// Create a [`Rtc`] from the configuration.
2393    pub fn build(self) -> Rtc {
2394        Rtc::new_from_config(self)
2395    }
2396}
2397
2398impl BweConfig {
2399    fn new(initial_bitrate: Bitrate) -> Self {
2400        Self {
2401            initial_bitrate,
2402            enable_loss_controller: false,
2403        }
2404    }
2405}
2406
2407impl Default for RtcConfig {
2408    fn default() -> Self {
2409        Self {
2410            local_ice_credentials: None,
2411            crypto_provider: CryptoProvider::process_default().unwrap_or(CryptoProvider::OpenSsl),
2412            dtls_cert_config: Default::default(),
2413            fingerprint_verification: true,
2414            ice_lite: false,
2415            initial_stun_rto: None,
2416            max_stun_rto: None,
2417            max_stun_retransmits: None,
2418            codec_config: CodecConfig::new_with_defaults(),
2419            exts: ExtensionMap::standard(),
2420            stats_interval: None,
2421            bwe_config: None,
2422            reordering_size_audio: 15,
2423            reordering_size_video: 30,
2424            send_buffer_audio: 50,
2425            send_buffer_video: 1000,
2426            rtp_mode: false,
2427            enable_raw_packets: false,
2428        }
2429    }
2430}
2431
2432impl PartialEq for Event {
2433    fn eq(&self, other: &Self) -> bool {
2434        match (self, other) {
2435            (Self::IceConnectionStateChange(l0), Self::IceConnectionStateChange(r0)) => l0 == r0,
2436            (Self::MediaAdded(m0), Self::MediaAdded(m1)) => m0 == m1,
2437            (Self::MediaData(m1), Self::MediaData(m2)) => m1 == m2,
2438            (Self::ChannelOpen(l0, l1), Self::ChannelOpen(r0, r1)) => l0 == r0 && l1 == r1,
2439            (Self::ChannelData(l0), Self::ChannelData(r0)) => l0 == r0,
2440            (Self::ChannelClose(l0), Self::ChannelClose(r0)) => l0 == r0,
2441            _ => false,
2442        }
2443    }
2444}
2445
2446impl Eq for Event {}
2447
2448impl fmt::Debug for Rtc {
2449    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2450        f.debug_struct("Rtc").finish()
2451    }
2452}
2453
2454/// Log a CSV like stat to stdout.
2455///
2456/// ```ignore
2457/// log_stat!("MY_STAT", 1, "hello", 3);
2458/// ```
2459///
2460/// will result in the following being printed
2461///
2462/// ```text
2463/// MY_STAT 1, hello, 3, {unix_timestamp_ms}
2464/// ````
2465///
2466/// These logs can be easily grepped for, parsed and graphed, or otherwise analyzed.
2467///
2468/// This macro turns into a NO-OP if the `_internal_dont_use_log_stats` feature is not enabled
2469macro_rules! log_stat {
2470    ($name:expr, $($arg:expr),+) => {
2471        #[cfg(feature = "_internal_dont_use_log_stats")]
2472        {
2473            use std::time::SystemTime;
2474            use std::io::{self, Write};
2475
2476            let now = SystemTime::now();
2477            let since_epoch = now.duration_since(SystemTime::UNIX_EPOCH).unwrap();
2478            let unix_time_ms = since_epoch.as_millis();
2479            let mut lock = io::stdout().lock();
2480            write!(lock, "{} ", $name).expect("Failed to write to stdout");
2481
2482            $(
2483                write!(lock, "{},", $arg).expect("Failed to write to stdout");
2484            )+
2485            writeln!(lock, "{}", unix_time_ms).expect("Failed to write to stdout");
2486        }
2487    };
2488}
2489pub(crate) use log_stat;
2490
2491#[cfg(test)]
2492#[doc(hidden)]
2493pub fn init_crypto_default() {
2494    crate::config::CryptoProvider::from_feature_flags().__test_install_process_default();
2495}
2496
2497#[cfg(test)]
2498mod test {
2499    use std::panic::UnwindSafe;
2500
2501    use super::*;
2502
2503    #[test]
2504    fn rtc_is_send() {
2505        fn is_send<T: Send>(_t: T) {}
2506        fn is_sync<T: Sync>(_t: T) {}
2507        is_send(Rtc::new());
2508        is_sync(Rtc::new());
2509    }
2510
2511    #[test]
2512    fn rtc_is_unwind_safe() {
2513        fn is_unwind_safe<T: UnwindSafe>(_t: T) {}
2514        is_unwind_safe(Rtc::new());
2515    }
2516
2517    #[test]
2518    fn event_is_reasonably_sized() {
2519        let n = std::mem::size_of::<Event>();
2520        assert!(n < 450);
2521    }
2522}
2523
2524#[cfg(feature = "_internal_test_exports")]
2525#[allow(missing_docs)]
2526pub mod _internal_test_exports;