Reference

Audio Channels

← Back to Wire Protocol

Wire-level SDP/ICE spec for the two peer connections below. For a client-side code walkthrough instead, see Audio & Video Wiring in the System Internals Reference.

A WebRTC peer connection that publishes the mic. SDP/ICE are relayed over the Socket.IO socket (the asr-webrtc-* events in §4a/§4c), not over HTTP.

All SDP/ICE for this peer connection travels over the Socket.IO socket — there's no separate signaling channel to manage client-side. See below for why the server's remote candidate still forces TURN.

ICE config (implemented in SDK:wire.js iceConfig(); TURN URL list from the built-in client's media layer buildIceConfiguration). host below is the turnServerUrl value returned by appInit; the example uses turn.example.com. username/credential default to "kaltura"/"avatar" (SDK:wire.js turnServers()) and can be overridden via its creds param:

new RTCPeerConnection({
  iceServers: [{
    urls: [ "turn:turn.example.com:80?transport=udp",
            "turn:turn.example.com:443?transport=udp",
            "turn:turn.example.com:80?transport=tcp",
            "turns:turn.example.com:443?transport=tcp" ],
    username: "kaltura", credential: "avatar" }],
  iceTransportPolicy: <see matrix below>,
  bundlePolicy: "max-bundle"
})

Either resolves to the same media path. The server's only ICE candidate is a private 10.x typ host, unreachable directly, so the selected pair is relay↔host through TURN regardless. 'relay' forces that. 'all' also gathers host/srflx but still ends up on the relay pair. On Firefox both clients force 'all' (relay-only candidate handling differs in the built-in client's media layer).

When an agent runs in audio/phone mode (no STV video — see §6), the runtime negotiates a single bidirectional audio peer. This uses a different event family than the asr-webrtc-* mic uplink. Here the server creates the offer:

Direction Event Payload Meaning
→ webrtc-create-offer {} Ask the server to start audio-mode WebRTC (server replies with webrtc-offer).
← webrtc-offer { offer } Server-generated SDP offer.
→ webrtc-answer { answer } Client SDP answer.
→ / ← webrtc-ice-candidate { candidate } ICE trickle, both directions.
← webrtc-connected / webrtc-disconnected {} Audio peer state.
← webrtc-error { error } Audio-mode negotiation error.

This is distinct from §5 (where the client offers the mic uplink and STT runs server-side). SDK implements the §5 path (video agents). Audio-mode is documented here for completeness.

In audio mode, the server itself is the far end of this peer connection. This differs from the asr-webrtc-* uplink in §5, where the client creates the offer. Here the server creates the offer and sends synthesized speech to the browser over this same connection.

A receive-only WebRTC peer connection fed via WHEP (WebRTC-HTTP Egress Protocol). Signaling is plain SDP over HTTP, independent of the socket. (Server-side, STV renders the face and streams it into the media relay that provides the WHEP egress. See Platform Overview.)

cast_mode selects the STV egress (StvCastMode enum "webrtc"\|"rtmp", optional in the stvNewSession body). This SDK never sends it. buildStvNewSession() (SDK:wire.js) accepts an optional castMode argument, but session.js's one call site never passes one. So this SDK only ever takes the server's fully-omitted-default path, not either named value:

The URL shape alone doesn't tell you which path is safe — the guard above checks the resolved host, not the shape. The client POSTs whichever webrtc_url the server returns, verbatim. The browser always plays via WebRTC/WHEP regardless of mode — "rtmp" is only the server-side ingest the renderer uses, never a browser transport.

ICE config: same TURN URL block as §5. STV resolves forceStvRelay && !isFirefox ? 'relay' : 'all'. All three clients agree here — the platform's built-in client (forceStvRelay:true), the embed client (default 'relay'), and SDK (SDK:wire.js iceConfig()) — so:

iceTransportPolicy: "relay"     // STV → 'relay' (non-Firefox); 'all' on Firefox
bundlePolicy: "max-bundle"

Teardown = DELETE to the WHEP resource named by the 201's Location header. That header is path-absolute from the media server's own root (/whep/session/{session_id}/viewer/{viewer_id}), so it carries none of the path prefix the subscribe URL has: the release URL is the POSTed subscribe URL plus the header's /viewer/… suffix (SDK:wire.js whepResourceUrl()). An absolute Location is used as-is, and any other relative one (the srsBaseUrl fallback form's ?action=delete shape) resolves against the subscribe URL the usual way. Resolving a /viewer/… header against the origin instead drops the prefix, and the DELETE misses: the viewer slot stays held until the server releases the session on its own.

WHEP status codes:

Code Meaning
201 Created
404 No active session (must re-create)
409 Already has a viewer
415 Wrong content-type
Doc Covers
Wire Protocol · Connection Basics The connect sequence these two channels plug into
Wire Protocol · Events Catalog The asr-webrtc-* signaling events referenced above
Wire Protocol Back to the index
Click to talk with Nova — she knows this whole SDK.
Nova AI assistant — knows this whole site

Reloading starts a fresh chat. “New conversation” does the same without leaving the drawer.