Skip to main content

Transport architecture

Orbit’s real-time media rides two planes, split by where the media originates, not by a per-call flag you set:
  • Orbit Media (SFU) carries WebRTC media — video rooms and the browser softphone.
  • Jambonz SBC + RTPengine carries PSTN/SIP carrier media — inbound DIDs and outbound calls.
A single call can span both planes (a browser softphone dialling a PSTN number rides Orbit Media for the browser leg and is bridged through Jambonz to the carrier). There is no transport request field and no per-call SFU-vs-bridge decision the API makes on your behalf — the plane follows directly from the endpoint and the leg type.

TL;DR

Every below-300ms hop in a real-time session lives on exactly one of the two planes, and a call that crosses between browser and carrier spans both. Pick the endpoint for the experience you want — the plane follows: video rooms always ride the SFU, PSTN legs always ride Jambonz, and the softphone is the one surface where your SDK picks between the SFU and a SIP-over-WSS gateway. The scenario-by-scenario picking table lives in Media planes; this page covers the deeper architecture of both planes.

Media paths per scenario

The diagram differs per entry point. Orbit never re-splits a leg once it lands on a plane — the only hybrid is the softphone-to-PSTN bridge. Browser softphone → PSTN (spans both planes):
The softphone room name is deterministic per user, and the bridge attaches Jambonz to that same room — so a reconnect rejoins the room the bridge is already anchored to instead of spooling up a second leg. See Leg bridging & the token model. Inbound DID → tenant handler (Jambonz plane only):
Inbound media terminates on the SBC as SIP. If the tenant’s handler delivers the call to a browser softphone, Jambonz bridges the carrier leg into the answering party’s SFU room; if it terminates on a SIP endpoint or in voicemail, the whole call stays on the Jambonz plane. Video room (SFU plane only):
A video room never touches Jambonz — recording is server-side SFU egress, and the room lives in one media region end to end. See Multi-region media routing for how the region is picked and why a room never silently moves regions.

Orbit Media (the SFU)

Orbit Media is Orbit’s Selective Forwarding Unit. It handles everything that needs server-side fan-out or mixing of WebRTC media: simulcast, per-subscriber bitrate adaptation, codec negotiation, DTLS/SRTP, and server-side recording via egress. Clients never talk to the SFU with a long-lived key. The API mints a short-lived join token scoped to a single room:
  • VideoPOST /api/v1/video/rooms and /api/v1/video/rooms-scheduled create a room and mint a participant token against Orbit Media. There is no non-SFU mode for video.
  • Voice (browser softphone)POST /api/v1/voice/softphone/token mints an Orbit Media token for a deterministic per-user room (softphone:<tenant>:<user>), so reconnects are idempotent. See Softphone token.
Recording for SFU sessions is produced by Orbit Media’s egress pipeline.

Jambonz SBC + RTPengine (carrier legs)

PSTN and SIP carrier media never touches the SFU. It terminates on the Jambonz session border controller, with RTPengine bridging RTP/SRTP between the carrier and Orbit:
  • Inbound — Telnyx and DIDWW DIDs route through Jambonz, which applies the tenant’s number-handler routing.
  • Outbound (MT)POST /api/v1/voice/calls initiates a call through Jambonz, which terminates it on the Devotel wholesale softswitch. Outbound voice exits only via Devotel — Orbit never wires a carrier’s call-control API for outbound termination.
In-call voice recording on this plane is SIPREC (POST /api/v1/voice/calls/:id/recording/start), not SFU egress.

Leg bridging & the token model

“Bridging” here is concrete, not architectural hand-waving: Jambonz is the SIP endpoint that joins two otherwise disjoint media domains.
  • The SFU side — the browser client holds a short-lived join token and publishes/subscribes audio in its Orbit Media room via DTLS/SRTP.
  • The bridge — Jambonz attaches to that room as a participant, converts the room’s WebRTC audio into a SIP leg, and maintains both the SFU-room membership and the carrier-side SIP dialog while the call is up.
  • The carrier side — RTPengine relays the resulting RTP/SRTP between Jambonz and the Devotel wholesale softswitch.
Credentials are deliberately asymmetric across the two softphone transports:
  • SFU pathPOST /api/v1/voice/softphone/token returns a short-lived room-scoped join token for the deterministic room softphone:<tenant>:<user>. Because the room name is derived from the tenant + user and the token endpoint pre-creates the room (idempotently, tolerating “room already exists”), a token refresh or a client reconnect rejoins the same room the Jambonz bridge is already anchored to. There is nothing to revoke: a token is a bearer credential that expires on its own.
  • SIP-over-WSS pathPOST /api/v1/voice/softphone/register issues a short-lived SIP credential (HMAC-derived password, never stored server-side) whose issuance metadata is persisted, so a tenant can revoke it ahead of expiry via DELETE /api/v1/voice/softphone/credentials/:username. The gateway rejects the credential on its next validation even while inside its nominal lifetime. This is the one transport where revocation matters — the credential is a SIP REGISTER ticket, not a one-shot join token.
Neither path gives a client a long-lived key, and neither path changes which plane the carrier leg lands on: the moment a call has a PSTN leg, that leg is on Jambonz.

Recording planes

Recording follows the plane the media rides — the two mechanisms are independent and never mix on the same leg: Voice recording has mid-call controls beyond start/stop — pause/resume keeps a single SIPREC session open and stamps the excluded window into call metadata, which is the CCaaS PCI/HIPAA pattern (exclude a card window without splitting the recording into files). A softphone call that crosses onto the carrier plane records on the carrier plane: SIPREC captures the bridged carrier leg, not the SFU room.

Failure & edge behavior

The transport architecture assumes clients disconnect, tokens expire mid-session, and uploads fail — the surfaces above are designed to degrade instead of corrupt:
  • Reconnects are idempotent by name. The softphone room is softphone:<tenant>:<user> — a reconnect rejoins the same room, and re-POSTing /softphone/token re-creates it if it was GC’d. The carrier-side bridge re-anchors to the same room name on reconnect, so a leg doesn’t fork into a duplicate.
  • Tokens expire; SIP credentials are revocable. SFU join tokens are short-lived and not revocable (they simply age out); SIP-over-WSS credentials can be revoked before expiry. Pick the transport whose failure mode you prefer — immediate expiry vs. explicitly revocable.
  • Recording upload failure doesn’t lose the recording. The recorder retries with backoff, marks a failed upload for operator triage rather than dropping it, and the API’s SIPREC callback is idempotent on retry — a duplicate completion for the same call updates the same recording record instead of creating a second one.
  • Mid-call media controls are leg-scoped. recording/start, dtmf, hold/unhold, warm-transfer etc. all operate on the active call leg via Jambonz mid-call updates — they affect the carrier-side dialog, not the SFU room membership.

What the API does not expose

To keep this page honest against the code, a few things that earlier drafts implied but the API does not do:
  • There is no transport field on the POST /api/v1/voice/calls body and no INVALID_TRANSPORT error code. The plane is implied by the endpoint and leg type.
  • There is no client-facing “decision tree” service that ranks SFU vs. WebSocket bridge per call, and no per-call latency-budget selection.
  • There is no API-controlled codec list, DTX toggle, or per-call RTP profile — codec negotiation is internal to each plane’s signaling and isn’t a request parameter.
  • There is no cross-region failover tunable per call — a room lives in one media region end to end (see Multi-region media routing), and the carrier plane doesn’t expose a route-choice request field.

Browser softphone

The browser softphone has two client transports, chosen by the SDK in use — not by a request flag:
  • Orbit Media (WebRTC) — the dashboard softphone calls POST /api/v1/voice/softphone/token and joins an Orbit Media room.
  • SIP over WSS — the @devotel-orbit/web Softphone calls POST /api/v1/voice/softphone/register to obtain a short-lived SIP credential and REGISTERs against Orbit’s WebRTC-to-SIP gateway over a secure WebSocket. The SIP password itself is HMAC-derived and never stored, but issuance and revocation metadata (issue/expiry times, the owning org, and a revoked flag) is persisted server-side so a tenant can revoke a credential before it expires. Call DELETE /api/v1/voice/softphone/credentials/:username to revoke one — the gateway rejects the HMAC on its next validation even while it’s still within its lifetime.
Either way the carrier leg, when one exists, is bridged through Jambonz as described above.

Cross-references