Skip to main content
Version: 0.26.0

Simulcast

This guide shows how to enable simulcast (multi-quality video streaming) so that senders publish multiple quality variants and receivers can independently choose which variant to receive.

Prerequisites

Before configuring simulcast, you must be connected to a room with video enabled.

tip

For a conceptual overview of how simulcast works, including when to use it and how variants flow through the server, see Simulcast.


Step 1: Configure sent qualities (sender side)

Pass sentQualities in the videoConfig prop of FishjamProvider to control which quality variants the sender publishes.

function App() { return ( <FishjamProvider fishjamId={fishjamId} videoConfig={{ sentQualities: [ Variant.VARIANT_LOW, Variant.VARIANT_MEDIUM, Variant.VARIANT_HIGH, ], }} > {/* your app */} </FishjamProvider> ); }

To disable simulcast entirely, pass false:

function App() { return ( <FishjamProvider fishjamId={fishjamId} videoConfig={{ sentQualities: false }} > {/* your app */} </FishjamProvider> ); }

Step 2: Select received quality (receiver side)

Remote tracks expose setReceivedQuality, which tells the server which variant to forward for that track.

function RemoteVideos() { const { remotePeers } = usePeers(); return ( <div> {remotePeers.map((peer) => peer.tracks.map((track) => ( <div key={track.trackId}> <VideoPlayer stream={track.stream} /> <QualitySelector track={track} /> </div> )), )} </div> ); }

Step 3: Call setReceivedQuality based on your needs

In practice, you would call setReceivedQuality based on your application's state. For example, you could request high quality for a full-screen participant and low quality for thumbnails in a grid. The manual quality selector below is a simplified example to illustrate the API:

import React from "react"; import { type RemoteTrack, Variant } from "@fishjam-cloud/react-client"; const variants = [ { label: "Low", value: Variant.VARIANT_LOW }, { label: "Medium", value: Variant.VARIANT_MEDIUM }, { label: "High", value: Variant.VARIANT_HIGH }, ]; function QualitySelector({ track }: { track: RemoteTrack }) { return ( <div> {variants.map(({ label, value }) => ( <button key={label} onClick={() => track.setReceivedQuality(value)}> {label} </button> ))} </div> ); }

Type differences: Track vs RemoteTrack

When using usePeers, the track types differ between local and remote peers:

  • localPeer.tracks are typed as Track (no quality selection methods)
  • remotePeers[].tracks are typed as RemoteTrack (extends Track with setReceivedQuality)

This means setReceivedQuality is only available on tracks from remote peers, which is the correct behavior. You don't need to select a quality variant for your own video.


See also