Transports

Keep one Iroh session while choosing direct, WebRTC, or MoQ packet paths

OpenRTC separates coordination from payload. The Cloudflare gateway establishes the scoped avenue; Rust owns admission, the peer session, path proof, replacement, retry, and recovery in native and browser/WASM runtimes.

Most applications should omit transports. OpenRTC starts one Iroh endpoint and chooses its normal direct or relay path automatically.

Use direct-only mode only when the application accepts failed connections on networks that require a relay:

const rtc = OpenRTC({
  apiKey,
  transports: { webrtc: true, relay: false },
});
use openrtc::client::TransportConfig;

let transports = TransportConfig {
    relay: false,
    ..Default::default()
};

Both forms must be applied before the Iroh endpoint starts. They remove Iroh relay, TURN, and MoQ routes while retaining eligible direct routes. See the transport API reference for portal precedence, defaults, and rate-limit semantics.

const rtc = OpenRTC({
  apiKey,
  transports: {
    webrtc: true,
    moq: {
      relayUrl: 'https://draft14-relay.example.com/moq',
      accessToken: await shortLivedMoqToken(),
    },
  },
});

WebRTC and MoQ are Iroh packet carriers. Application code keeps using the same Iroh streams and channels regardless of which physical carrier Rust selects.

Carrier negotiation reuses the admitted peer control stream. It does not open another gateway socket, presence subscription, device row, or cloud retry loop. The current admitted Iroh path stays usable until a generation-current carrier passes protected proof and is committed atomically. Network changes, wake, background/resume, and carrier failure wake that same Rust owner; delayed work from retired generations is ignored.

webrtc: true is the minimal WebRTC-carrier switch. MoQ requires an explicit relay URL. There is no separate implementation selector or external application-data upgrade.

When both carriers are configured, OpenRTC does not start both. The Rust peer-session policy chooses one mutually supported carrier from the exact route priority and advances only after terminal failure. This avoids duplicate transport setup and negotiation traffic.

use openrtc::client::{Client, MoQConfig, TransportConfig, WebRTCConfig};

let transports = TransportConfig {
    relay: true,
    webrtc: Some(WebRTCConfig {
        lan_mode: true,
        ..Default::default()
    }),
    moq: Some(MoQConfig {
        relay_url: "https://draft14-relay.example.com/moq".into(),
        access_token: short_lived_moq_token(),
    }),
    optimize_for: openrtc::route_policy::RouteOptimization::Balanced,
    route_priority: vec![
        openrtc::route_policy::KnownRoute::IrohLan,
        openrtc::route_policy::KnownRoute::IrohQuic,
        openrtc::route_policy::KnownRoute::IrohWebRtc,
        openrtc::route_policy::KnownRoute::IrohMoq,
        openrtc::route_policy::KnownRoute::IrohRelay,
    ],
    ..Default::default()
};

let client = Client::builder(api_key, identity)?
    .transport_config(transports)
    .signaling_backend(avenue.signaling())
    .build();

WebRTC carriers use the negotiated unreliable, unordered data channel openrtc-iroh-packets-v1 (ID 1). MoQ carriers require an explicit compatible Draft 14 relay and use FIFO, send-complete subgroup objects; credentials must remain separate from the relay URL.

Direct application payload does not consume relay credits. Managed relay usage is measured and shown in the Developer Portal.

Privacy and latency policy

TypeScript uses privacy: 'relay-only'; Rust uses TransportConfig::privacy_mode. Both remove direct Iroh and nearby routes, disable BLE/local discovery, and require relay-only WebRTC ICE. This provides peer-address privacy, not anonymity from service operators or account systems. The policy fails closed when no eligible relay route succeeds.

TransportConfig::iroh_relay_only is the advanced, Iroh-only endpoint switch. It does not silently constrain WebRTC, MoQ, BLE, or exact route priority.

For latency-sensitive native applications, set RouteOptimization::LowestLatency. OpenRTC compares passive, proven Iroh and WebRTC RTTs without creating another probe loop. It changes preference only for an improvement of at least 20 ms, after five seconds of candidate stability, a 30-second current-route hold, and with samples at most ten seconds old. Browser carriers continue to use deterministic priority because inactive carrier measurement would create the very parallel traffic this policy avoids.

Transport state is host-reported. Do not infer native WebRTC, MoQ, LAN, or BLE capability from TypeScript constants.