nimeet Docs
中文

Simulcast, Fallback and Bandwidth Control

Dual-stream/simulcast layers, subscription fallback, dynacast, encoding parameters and bandwidth estimation.

Version v1.1.0 · Updated 2026-10-26 · revision 1

On a poor network the most important thing is not "turn the bitrate down" but letting every endpoint choose what to watch according to its own bandwidth. This page covers dual-stream/simulcast, subscription fallback, dynamic subscription and encoder parameters, plus the exact method names they use in your code.

Four concepts

ConceptWhat it doesWeb method
Dual streamThe publisher sends a high and a low stream at the same time; subscribers pick according to bandwidthenableDualStream() / setDualStreamMode(mode, streamParameter)
Subscription fallbackDegrades automatically to the low stream, then to audio only, when bandwidth is insufficientsetStreamFallbackOption(uid, fallbackType)
Remote stream typeChoose manually whether to watch the high or the low streamsetRemoteVideoStreamType(uid, streamType) / setRemoteDefaultVideoStreamType(streamType)
Low-stream parametersControl the resolution, frame rate and bitrate ceiling of the low streamsetLowStreamParameter(streamParameter)

Typical configuration

javascript
import AgoraRTC from '@nimeet/rtc-web';

const client = AgoraRTC.createClient({ mode: 'rtc' });
await client.join(appId, 'weekly-sync', token, uid);

// 1) Enable dual stream on the publisher (takes effect when set before publishing)
client.setLowStreamParameter({ width: 320, height: 180, framerate: 15, bitrate: 150 });
await client.enableDualStream();

// 2) Subscriber side: degrade to the low stream, then to audio only, when the network is poor
await client.setStreamFallbackOption(remoteUid, 2);

// 3) Or control it manually: subscribe to the low stream only
await client.setRemoteVideoStreamType(remoteUid, 1);   // 1 = low stream

// 4) Global default: newly appearing remote users start on the low stream (raise it per user for large layouts)
await client.setRemoteDefaultVideoStreamType(1);

When to use which

ScenarioRecommendation
1v1 callNo dual stream needed; just tune encoderConfig to the bandwidth
Small class (< 10 people)The presenter sends the high stream, everyone else subscribes to the low stream, setStreamFallbackOption(uid, 2)
Large class/live streaming (many viewers)All viewers take the low stream or audio only; the host enables dual stream
Screen-sharing demosThe shared stream prefers sharpness, the camera stream uses the low stream
Mobile on a poor networkSubscribe to the low stream with audio-only fallback, together with audio volume indication

Encoder parameters

javascript
// Set when the camera track is created
const cameraTrack = await AgoraRTC.createCameraVideoTrack({
  encoderConfig: { width: 1280, height: 720, frameRate: 20, bitrateMax: 1500 },
});

// Adjust while running (supported on some platforms)
cameraTrack.setEncoderConfiguration({ width: 640, height: 360, frameRate: 15 });
ParameterSuggested valueNotes
Resolution1v1: 720p; small class: 640×360 or 720p; large-class viewers: no video subscriptionResolution has the biggest impact on bandwidth
Frame rate15–20fps (content) / 24–30fps (people)Dropping to 15fps usually feels worse than lowering resolution
Bitrate ceiling360p ≈ 500kbps, 720p ≈ 1.5MbpsConsistent with the server-side usage metering
Degradation preferencemaintain-framerate / maintain-resolution / balancedScreen sharing prefers sharpness, people prefer frame rate

Events and observability

EventPurpose
stream-fallbackA user's stream fell back (you can hint that "the other side's network is poor")
stream-type-changedSwitching between the high and low stream completed
network-qualityPeriodic uplink/downlink quality report (levels 1–6)
getRTCStats()Local and remote statistics, with the same field definitions as Crystal Ball

Report these events to POST /v1/analytics/quality to see the quality curves in Crystal Ball (example 09-quality-ingest.mjs).

Common issues

SymptomCauseHandling
enableDualStream reports NOT_SUPPORTEDThe current media stack does not provide simulcastSwitch to a single stream and tune the encoder parameters to the bandwidth
The picture still stutters after switching to the low streamThe high stream is still subscribed and was not releasedCall setRemoteVideoStreamType first, then watch stream-type-changed
No fallback happensThe publisher did not enable dual streamFallback requires a low stream to exist
High CPU on the viewer sideToo many high streams are subscribedDefault to the low stream and subscribe only to visible users
The bitrate will not come downEncoder parameters were fixed when the track was initialisedSet them when creating the track; runtime adjustment is not supported on every platform

Generated by the documentation build pipeline · 2026-10-31 01:24:02 UTC · Documentation center v1.1.0.

Content follows the public API definitions.

ni-meet is a self-hosted RTC PaaS with a LiveKit-based media plane (Apache-2.0) and an Agora-compatible API.