Skip to main content
The WebRTC endpoint is another transport for the Stream API. It uses a WebSocket only for signaling, then carries Stream control messages over a WebRTC data channel and audio over WebRTC media tracks. This page covers the connection layer: WebSocket signaling, SDP offer/answer, trickle ICE, tracks, and connection lifetime. For the application message layer, including init, configure, flush, and server events, see the Stream message layer.

Endpoint

Authenticate with one query parameter:
Authentication is checked before the WebSocket upgrade. If authentication fails, the server returns HTTP 401 rather than opening a WebSocket and sending a close frame.

Transport Model

  • The signaling WebSocket is used for SDP and ICE only.
  • Keep the signaling WebSocket open for the lifetime of the WebRTC session. If it closes, the service closes the associated peer connection.
  • The client creates the WebRTC data channel. The service accepts the incoming data channel and uses it for Stream v3 JSON messages.
  • The JS client uses a data channel named messaging; the service accepts any label.
  • Client microphone audio is sent as a WebRTC audio media track.
  • Server translation audio is returned as a WebRTC audio media track.
  • The WebRTC audio codec is Opus.

Connection Flow

The service supports one SDP offer per signaling WebSocket. To reconnect after closing or failing a peer connection, open a new WebSocket and create a new peer connection.

Signaling Messages

Signaling messages are JSON text frames on the WebSocket. The signaling layer has only four message kinds:
  • Client to server: offer
  • Server to client: answer
  • Either direction: candidate
  • Either direction: end-of-candidates
The answer includes the generated session_id and service version. The message shapes intentionally mirror browser WebRTC concepts: SDP descriptions contain an sdp string, and ICE candidates use the standard candidate JSON shape returned by browser APIs such as RTCIceCandidate.toJSON(). Do not send Stream v3 messages on the signaling WebSocket. Send them on the WebRTC data channel after it opens.

Trickle ICE

Use trickle ICE. Do not wait for ICE gathering to complete before sending the offer. On the client:
  1. Send the SDP offer as soon as createOffer() and setLocalDescription() complete.
  2. Send each icecandidate event to the service as a candidate signal.
  3. When the browser emits an icecandidate event with a null candidate, send end-of-candidates.
  4. Apply each server candidate with addIceCandidate().
  5. Treat server end-of-candidates as the remote end-of-candidates marker.
The service handles candidate timing as follows:
  • Remote ICE candidates received before the service has accepted the offer are queued and applied after the offer is processed.
  • Local ICE candidates gathered by the service before the answer is sent are queued and flushed immediately after the answer.
  • When service-side ICE gathering completes, the service sends end-of-candidates.
This means candidates can be sent immediately as they are discovered, even while the offer/answer exchange is still in progress.

Peer Connection Setup

The JS client creates the peer connection with bundlePolicy: "max-bundle", creates a data channel named messaging, and adds the caller-provided audio track before creating the offer:
Use one data channel for Stream v3 JSON messages. Audio should stay on media tracks, not on the data channel.

ICE Servers And Networking

The service gathers IPv4 UDP candidates and is configured with public STUN servers. In deployed environments it can also use Metered TURN when TURN_USERNAME and TURN_PASSWORD are configured. The JS client currently uses the browser’s default ICE configuration and relies on the service-side ICE configuration. Custom clients may provide their own iceServers configuration. Include TURN for production clients that need to work on mobile networks, corporate networks, VPNs, or any environment where direct UDP may be blocked. Without TURN, peer connections can fail on relay-only networks. The service uses a bounded UDP port range. Locally this defaults to 10000-60000; deployed environments may choose a narrower range. Make sure the selected UDP range is reachable from clients or from the configured TURN relay.

Receiving Server Media

The service adds its outbound translation audio track before answering. Listen for the browser track event and attach the received stream to an audio output:
The server encodes output audio as Opus over WebRTC. The Stream v3 data channel still emits text and lifecycle events such as transcription, translation, and boundaries; the audio bytes themselves are not sent as Stream v3 binary frames when using WebRTC.

Minimal Browser Signaling Skeleton

This intentionally omits the Stream v3 message contents. After the data channel opens, follow the Stream message layer for the JSON messages to send and receive.

Operational Notes

  • Non-text WebSocket frames are ignored, except close frames, which end the session.
  • If the peer connection enters disconnected or failed, the service allows a reconnect grace period before closing the session.
  • Idle sessions are closed after the configured inactivity timeout.
  • Renegotiation is not supported on an existing signaling WebSocket. Start a new session instead.