qrtc quantum realtime communication GitHub

Using the API

The API mirrors RTCPeerConnection, with one difference in shape: media arrives already encoded (video) or as PCM (audio), and events arrive through a single callback. The generated reference is under API reference.

Engine and peer

Create one NativeEngine per process. It owns a private tokio runtime, so the consumer needs no runtime of its own. Each create_peer call starts one driver task.

use qrtc::{native::NativeEngine, PeerEngine, PeerEvent, RtcConfiguration};
use std::sync::Arc;

let engine = NativeEngine::new()?;
let config: RtcConfiguration = serde_json::from_str(r#"{
    "iceServers": [{ "urls": "turns:turn.example.org:443", "username": "u", "credential": "p" }],
    "postQuantum": "prefer"
}"#)?;
let peer = engine.create_peer(&config, Arc::new(|event: PeerEvent| {
    // Called on engine threads, in order for this peer connection.
}))?;

Every Peer method blocks until the driver answers. From async code, call them on a blocking pool such as tokio::task::spawn_blocking.

Configuration

RtcConfiguration deserializes from the JSON a page passes to new RTCPeerConnection(), with two additions.

Field (JSON)Meaning
iceServersSTUN and TURN servers. urls is a string or an array; turn: with ?transport=tcp, and turns:, use a stream.
iceTransportPolicy"all" or "relay"
bundlePolicy"balanced", "max-compat" or "max-bundle"
videoCodecsNot W3C. Video codecs the consumer can encode and decode: "vp8", "h264". Absent means VP8 only.
postQuantumNot W3C. "off", "prefer" or "require"; see policies. Absent means default_pq_policy().

A connection, step by step

  1. Describe transceivers. Call upsert_transceiver with a whole TransceiverSpec each time one changes: id, kind, direction, stream ids, sender track id, whether addTrack made it, codec preferences. The consumer picks ids below REMOTE_TX_BASE (0x8000_0000); the engine numbers transceivers that a remote offer creates from there up.
  2. Open data channels. create_data_channel returns a DataChannelInfo with an opaque DcHandle. The SCTP id may still be unknown; PeerEvent::DcOpen carries it.
  3. Negotiate. create_offer, set_local_description, then send the SDP through your signalling. On the other side, set_remote_description, create_answer, set_local_description. Both setters return a TransceiverState per transceiver: mid, current and remote direction, remote stream and track ids. Use them to fire track and removetrack.
  4. Trickle candidates. PeerEvent::IceCandidate gives local candidates, then None at the end. Remote ones go to add_ice_candidate.
  5. Send media. Push 48 kHz mono PCM with push_pcm for an audio sender; send encoded video with send_frame. Received audio arrives as PeerEvent::AudioPcm, received video as PeerEvent::MediaFrame.
  6. Close. close() stops the driver and releases its sockets.

Events

PeerEvent serializes with a type tag named after the W3C event it drives. The media and message variants skip serialization: they carry bytes, so a consumer handles them directly.

VariantW3C counterpart
IceCandidateicecandidate
IceGatheringStateChange, IceConnectionStateChange, ConnectionStateChange, SignalingStateChangeThe matching *statechange events
NegotiationNeedednegotiationneeded
DataChannel, DcOpen, DcClose, DcError, DcBufferedAmountLow, DcMessagedatachannel, and the channel's open, close, error, bufferedamountlow, message
MediaFrame, AudioPcmWhat a receiver's track carries
KeyframeRequest, TargetBitrateEncoder feedback, no event
EncodedOutFrames for an RTCRtpScriptTransform

Audio controls

Errors

Every fallible method returns qrtc::Error. dom_name() gives the DOMException name to throw:

VariantDOMExceptionTypical cause
InvalidStateInvalidStateErrorWrong signalling state, closed connection
OperationOperationErrorThe engine could not complete the step
NotSupportedNotSupportedErrorA post-quantum policy without a post-quantum feature
SyntaxSyntaxErrorMalformed SDP, candidate or ICE server URL
InvalidModificationInvalidModificationErrorA local description edited structurally

Cargo features

FeatureDefaultEffect
turn-tls-ringyesTURN over TLS with rustls on ring (compiles C and assembly)
turn-tls-rustcryptonoTURN over TLS with rustls on RustCrypto; no C in the build
pq-modulettoyesPost-quantum groups with moduletto ML-KEM, plus the ML-KEM-512 groups
pq-hybridnoPost-quantum groups with RustCrypto ml-kem

A fully pure Rust build: default-features = false, features = ["turn-tls-rustcrypto", "pq-hybrid"]. With no TLS feature, turns: servers are skipped. With no post-quantum feature, DTLS stays at 1.2.

A runnable peer

examples/stdio_peer.rs is a complete peer that speaks JSON lines on standard input and output. The Chromium interop test drives it; it is also the shortest full example of the API.

cargo run --example stdio_peer