pub struct Rtc { /* private fields */ }Expand description
Instance that does WebRTC. Main struct of the entire library.
Usage
let mut rtc = Rtc::new();
loop {
let timeout = match rtc.poll_output().unwrap() {
Output::Timeout(v) => v,
Output::Transmit(t) => {
// TODO: Send data to remote peer.
continue; // poll again
}
Output::Event(e) => {
// TODO: Handle event.
continue; // poll again
}
};
// TODO: Wait for one of two events, reaching `timeout`
// or receiving network input. Both are encapsualted
// in the Input enum.
let input: Input = todo!();
rtc.handle_input(input).unwrap();
}Implementations§
source§impl Rtc
impl Rtc
sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new instance with default settings.
To configure the instance, use RtcConfig.
use str0m::Rtc;
let rtc = Rtc::new();sourcepub fn builder() -> RtcConfig
pub fn builder() -> RtcConfig
Creates a config builder that configures an Rtc instance.
let rtc = Rtc::builder()
.ice_lite(true)
.build();sourcepub fn is_alive(&self) -> bool
pub fn is_alive(&self) -> bool
Tests if this instance is still working.
Certain events will straight away disconnect the Rtc instance, such as
the DTLS fingerprint from the SDP not matching that of the TLS negotiation
(since that would potentially indicate a MITM attack!).
The instance can be manually disconnected using Rtc::disconnect().
let mut rtc = Rtc::new();
assert!(rtc.is_alive());
rtc.disconnect();
assert!(!rtc.is_alive());sourcepub fn disconnect(&mut self)
pub fn disconnect(&mut self)
Force disconnects the instance making Rtc::is_alive() return false.
This makes Rtc::poll_output and Rtc::handle_input go inert and not
produce anymore network output or events.
let mut rtc = Rtc::new();
rtc.disconnect();
assert!(!rtc.is_alive());sourcepub fn add_local_candidate(&mut self, c: Candidate)
pub fn add_local_candidate(&mut self, c: Candidate)
Add a local ICE candidate. Local candidates are socket addresses the Rtc instance
use for communicating with the peer.
This library has no built-in discovery of local network addresses on the host or NATed addresses via a STUN server or TURN server. The user of the library is expected to add new local candidates as they are discovered.
In WebRTC lingo, the Rtc instance is permanently in a mode of Trickle Ice. It’s
however advisable to add at least one local candidate before commencing SDP negotiation.
let mut rtc = Rtc::new();
let a = "127.0.0.1:5000".parse().unwrap();
let c = Candidate::host(a).unwrap();
rtc.add_local_candidate(c);sourcepub fn add_remote_candidate(&mut self, c: Candidate)
pub fn add_remote_candidate(&mut self, c: Candidate)
Add a remote ICE candidate. Remote candidates are addresses of the peer.
Remote candidates are typically added via receiving a remote Offer or Answer.
However for the case of Trickle Ice, this is the way to add remote candidaes
that are “trickled” from the other side.
let mut rtc = Rtc::new();
let a = "1.2.3.4:5000".parse().unwrap();
let c = Candidate::host(a).unwrap();
rtc.add_remote_candidate(c);sourcepub fn ice_connection_state(&self) -> IceConnectionState
pub fn ice_connection_state(&self) -> IceConnectionState
Checks current connection state. This state is also obtained via
Event::IceConnectionStateChange.
More details on connection states can be found in the ICE RFC.
let mut rtc = Rtc::new();
assert_eq!(rtc.ice_connection_state(), IceConnectionState::New);sourcepub fn create_change_set(&mut self) -> ChangeSet<'_>
pub fn create_change_set(&mut self) -> ChangeSet<'_>
Make changes to the Rtc session. This is the entry point for making an Offer.
The resulting ChangeSet encapsulates changes to the Rtc session that will
require an SDP negotiation.
The ChangeSet allows us to make multiple changes in one go. Calling
ChangeSet::apply() doesn’t apply the changes, but produces the Offer
that is to be sent to the remote peer. Only when the the remote peer responds with
an Answer can the changes be made to the session. The call to accept the answer
is PendingChanges::accept_answer().
How to send the Offer to the remote peer is not up to this library. Could be websocket,
a data channel or some other method of communication. See examples for a combination
of using HTTP POST and data channels.
let mut rtc = Rtc::new();
let mut changes = rtc.create_change_set();
let mid_audio = changes.add_media(MediaKind::Audio, Direction::SendOnly, None);
let mid_video = changes.add_media(MediaKind::Video, Direction::SendOnly, None);
let offer = changes.apply().unwrap();
let json = serde_json::to_vec(&offer).unwrap();sourcepub fn accept_offer(&mut self, offer: Offer) -> Result<Answer, RtcError>
pub fn accept_offer(&mut self, offer: Offer) -> Result<Answer, RtcError>
Accept an Offer from the remote peer. If this call returns successfully, the
changes will have been made to the session. The resulting Answer should be
sent to the remote peer.
Note. Rtc::pending_changes() from a previous non-completed ChangeSet are
rolled back when calling this function.
The incoming SDP is validated in various ways which can cause this call to fail.
Example of such problems would be an SDP without any m-lines, missing a=fingerprint
or if a=group doesn’t match the number of m-lines.
// obtain offer from remote peer.
let json_offer: &[u8] = todo!();
let offer: Offer = serde_json::from_slice(json_offer).unwrap();
let mut rtc = Rtc::new();
let answer = rtc.accept_offer(offer).unwrap();
// send json_answer to remote peer.
let json_answer = serde_json::to_vec(&answer).unwrap();sourcepub fn pending_changes(&mut self) -> Option<PendingChanges<'_>>
pub fn pending_changes(&mut self) -> Option<PendingChanges<'_>>
Obtain pending changes from a previous Rtc::create_change_set() call.
The PendingChanges allows us to either accept a remote answer, or
rollback the changes.
When this function returns None there are no pending changes. Changes are
automatically rolled back on Rtc::accept_offer()
let mut rtc = Rtc::new();
let mut changes = rtc.create_change_set();
let mid = changes.add_media(MediaKind::Audio, Direction::SendOnly, None);
let offer = changes.apply().unwrap();
// send offer to remote peer, receive answer back
let answer: Answer = todo!();
let pending = rtc.pending_changes().unwrap().accept_answer(answer);sourcepub fn poll_output(&mut self) -> Result<Output, RtcError>
pub fn poll_output(&mut self) -> Result<Output, RtcError>
Poll the Rtc instance for output. Output can be three things, something to Transmit
via a UDP socket (maybe via a TURN server). An Event, such as receiving media data,
or a Timeout.
The user of the library is expected to continuously call this function and deal with
the output until it encounters an Output::Timeout at which point no further output
is produced (if polled again, it will result in just another timeout).
After exhausting the poll_output, the function will only produce more output again
when one of two things happen:
- The polled timeout is reached.
- New network input.
See Rtc instance documentation for how this is expected to be used in a loop.
sourcepub fn accepts(&self, input: &Input<'_>) -> bool
pub fn accepts(&self, input: &Input<'_>) -> bool
Check if this Rtc instance accepts the given input. This is used for demultiplexing
several Rtc instances over the same UDP server socket.
Input::Timeout is always accepted. Input::Receive is tested against the nominated
ICE candidate. If that doesn’t match and the incoming data is a STUN packet, the accept call
is delegated to the ICE agent which recognises the remote peer from a=ufrag/a=password
credentials negotiated in the SDP.
In a server setup, the server would try to find an Rtc instances using Rtc::accepts().
The first found instance would be given the input via Rtc::handle_input().
// A vec holding the managed rtc instances. One instance per remote peer.
let mut rtcs = vec![Rtc::new(), Rtc::new(), Rtc::new()];
// Configure instances with local ice candidates etc.
loop {
// TODO poll_timeout() and handle the output.
let input: Input = todo!(); // read network data from socket.
for rtc in &mut rtcs {
if rtc.accepts(&input) {
rtc.handle_input(input).unwrap();
}
}
}sourcepub fn handle_input(&mut self, input: Input<'_>) -> Result<(), RtcError>
pub fn handle_input(&mut self, input: Input<'_>) -> Result<(), RtcError>
Provide input to this Rtc instance. Input is either a Input::Timeout for some
time that was previously obtained from Rtc::poll_output(), or Input::Receive
for network data.
Both the timeout and the network data contains a std::time::Instant which drives
time forward in the instance. For network data, the intention is to record the time
of receiving the network data as precise as possible. This time is used to calculate
things like jitter and bandwidth.
It’s always okay to call Rtc::handle_input() with a timeout, also before the
time obtained via Rtc::poll_output().
let mut rtc = Rtc::new();
loop {
let timeout: Instant = todo!(); // rtc.poll_output() until we get a timeout.
let input: Input = todo!(); // wait for network data or timeout.
rtc.handle_input(input);
}sourcepub fn media(&mut self, mid: Mid) -> Option<Media<'_>>
pub fn media(&mut self, mid: Mid) -> Option<Media<'_>>
Get a Media instance for inspecting and manipulating media. Media has a 1-1
relationship with “m-line” from the SDP. The Media instance is used for media
regardless of current direction.
Apart from inspecting information about the media, there are two fundamental
operations. One is Media::writer() for writing outgoing media data, the other
is Media::request_keyframe() to request a PLI/FIR keyframe for incoming media data.
All media rows are announced via the Event::MediaAdded event. This function
will return None for any Mid until that event has fired. This
is also the case for the mid that comes from ChangeSet::add_media().
Incoming media data is via the Event::MediaData event.
let mut rtc = Rtc::new();
let mid: Mid = todo!(); // obtain Mid from Event::MediaAdded
let media = rtc.media(mid).unwrap();
// TODO write media or request keyframe.sourcepub fn channel(&mut self, id: ChannelId) -> Option<Channel<'_>>
pub fn channel(&mut self, id: ChannelId) -> Option<Channel<'_>>
Obtain handle for writing to a data channel.
This is first available when a ChannelId is advertised via Event::ChannelOpen.
The function returns None also for IDs from ChangeSet::add_channel().
Incoming channel data is via the Event::ChannelData event.
let mut rtc = Rtc::new();
let cid: ChannelId = todo!(); // obtain Mid from Event::ChannelOpen
let media = rtc.channel(cid).unwrap();
// TODO write data channel data.