A browser tab — or eventually a phone app — can place and answer calls, stream mic audio up, and play agent audio back, with telephony-grade latency and no SFU in the middle. This page maps how a client-side app reaches ClutchCall Voice: which transport carries the audio, how the SDK reuses the browser’s own encoder, and exactly what is shipped versus planned today. The short version: browser clients use QUIC directly. Encoded Opus frames travel over MoQT (Media-over-QUIC Transport) over WebTransport, on a single :443 connection to relay.clutchcall.dev. This is the same track substrate as every other leg of the call (voice/<sid>/{uplink,downlink}). There is no media SFU and no gateway round-trip on the audio path.

The transport ladder

The standing design is a ladder: QUIC/MoQT is first-class, with WebSocket (control/data) and WebRTC (media) as the fallbacks for networks where UDP is blocked or a browser lacks WebTransport. Know where each rung ships today. The ladder is complete in the native SDK cores, but the browser/TypeScript SDK is WebTransport-only right now.
On the browser today, if the QUIC/WebTransport path is unavailable, the SDK does not silently downgrade to WebSocket or WebRTC media. That rung is not yet shipped for the TypeScript client. The QUIC→WebSocket fallback ladder currently lives only in the native SDK cores. Plan browser deployments for a WebTransport-capable, UDP-reachable network. See Browser compatibility for the gate and the current matrix.

WebTransport: the browser-native QUIC path

WebTransport gives the browser a real QUIC connection; you run no UDP plumbing. The SDK’s MoqtClient dials relay.clutchcall.dev, negotiates the moqt-16 subprotocol, and returns immediately. It queues your publishes and subscribes and replays them once the session is up. It then auto-reconnects with capped backoff if the link drops. Audio then flows as MoQT objects on the call’s two tracks:
“Uplink” and “downlink” are defined from the caller’s point of view. Each track carries a capability tag that the relay routes on. Thus an ASR consumer, a recorder, or an AI agent can subscribe to a call’s audio without the publisher knowing they exist. That is the same wire model the server and telephony legs use; see Realtime tracks. Full setup, dev certificates via serverCertificateHashes, and the 127.0.0.1 local-dev gotcha live in WebTransport.

Reusing the browser’s audio pipeline (WebRTC diversion)

Browser voice sounds good because you keep the browser’s audio pipeline but not its transport. A loopback RTCPeerConnection runs the browser’s capture graph: echo cancellation, gain control, noise suppression, the Opus encoder, and the jitter buffer. An RTCRtpScriptTransform that runs in a Worker taps the encoded Opus frames and hands them to MoQT. The WebRTC ICE/DTLS/SRTP transport is never used; only its codec and processing are. Raw PCM never crosses the wire. Because the tap is at the encoded-frame layer, the relay only ever sees opaque payloads.
1

Capture and encode

captureMicrophone(publication) requests the mic with AEC/AGC/NS enabled, wires the loopback peer connection, and installs the Worker transform on the sender. The browser’s Opus encoder then runs on your audio.
2

Publish over QUIC/MoQT

The Worker reads each encoded frame off the transform’s readable stream and writes it to voice/<sid>/uplink as a MoQT object over WebTransport. The relay fans it to whatever the engine bridged the call to — a SIP leg, an agent, a recorder.
3

Subscribe and play back

Downlink Opus arrives on voice/<sid>/downlink. The SDK’s OpusPlayer decodes it with WebCodecs and renders it through an audio-worklet ring buffer. The buffer pads silence on underrun.
The encoded-frame tap is the only capture path. The legacy main-thread createEncodedStreams() branch was removed. If a browser lacks RTCRtpScriptTransform, captureMicrophone throws; it does not fall back to an untapped path. MoqtClient.connect also refuses when requireEncodedTransform is set. This is deliberate: it keeps the encoded-Opus guarantee (frame-level E2EE readiness) intact.
The one-call helper and its options are in One-line WebRTC diversion; the capture internals and codec details are in Browser audio capture.

Mobile apps

Native iOS/Android transport is planned, not shipped. There is no Swift or Kotlin SDK today. The planned path is a portable QUIC/MoQT client compiled through a shared C++ FFI (per-ABI .so on Android, static .a on iOS, and a .jslib shim for WebGL builds). To ship to phones now, run the app inside a WebTransport-capable mobile browser view, or reach the engine through a server-side leg. Track status in Mobile app transport.

Where to go next

WebTransport

The browser-native QUIC path — connect, subprotocol, dev certs, and the track model in detail.

One-line WebRTC diversion

Divert an existing WebRTC audio pipeline onto QUIC with a single call.

RTCRtpScriptTransform

How the encoded-Opus tap works in a Worker, and why it is the only path.

Browser audio capture

Capture, encode, and publish mic audio — options, codecs, and playback.

Browser compatibility

What works where, the hard-gate, and the current fallback story.

Mobile app transport

The planned native path for carrying voice from iOS and Android apps.