RemoteAudioStream interface

extends AudioStream  REMOTE

A remote participant's microphone stream. Adds server-driven state, per-participant volume control, and audio level observation. Access via p.audio after subscribe().

Blueprint

Members added on top of AudioStream. Audio doesn't surface a degraded state and has no decoder-side observations.

interface RemoteAudioStream extends AudioStream { // State + level readonly streamState: "active" | "paused" | "ended"; readonly audioLevel: number; // Per-participant playback volume (SDK-managed audio element) setVolume(level: number): void; // === Events fired === // 'state-changed' ({ state }) โ€” every streamState transition }
Auto-played by default. SDK creates an internal <audio> element and plays remote audio automatically โ€” no manual attach needed for the common case. Use attach only for custom routing.

Properties (added)

Plus inherited from AudioStream: id, codec, isPlaying, isMuted, isEnded.

streamState

Server-driven routing state. See StreamState. Audio doesn't surface a degraded state โ€” audio is small enough that the server doesn't bandwidth-suppress it.

readonly streamState: "active" | "paused" | "ended"

audioLevel

Current sound level from this participant's mic, normalized 0..1. Sync getter โ€” poll at your desired interval (every 100ms is typical for speaking-ring UIs).

readonly audioLevel: number
Example โ€” speaking ring per participant
setInterval(() => {
  for (const p of room.remoteParticipants.values()) {
    const level = p.audio?.audioLevel ?? 0;
    updateSpeakingRing(p.id, level);   // CSS scale on a ring around the tile
  }
}, 100);

Methods (added)

Plus inherited from AudioStream: attach, getStats, getMediaStreamTrack.

setVolume

Set playback volume (0..1) for this remote participant's audio. Applies to the SDK-managed internal <audio> element.

setVolume(level: number): void
Parameters
  • level โ€” 0 (silent) to 1 (full volume). Values outside this range are clamped.
Example โ€” per-participant volume slider UI
volumeSlider.addEventListener('input', () => {
  p.audio.setVolume(volumeSlider.valueAsNumber);
});

Events

A single state-changed event covers every routing transition. Subscribe-completion events (audio-subscribed, audio-unsubscribed) fire on RemoteParticipant.

EventPayload
state-changed{ state: StreamState }

Fires when streamState changes. Audio surfaces only 'active', 'paused', and 'ended' โ€” no 'degraded' (audio isn't bandwidth-suppressed) and no decoder-side states ('frozen' / 'stuck' are RemoteVideoStream-only).

Example
p.audio.on('state-changed', ({ state }) => {
  if (state === 'ended') cleanupAudio(p);
});
For global output device routing (e.g. "send all audio to this headset"), use room.setOutputDevice() โ€” applies to all SDK-managed remote audio.

See also: AudioStream RemoteParticipant LocalAudioStream Room.setOutputDevice