Implementing simulcast with three quality layers in Chrome

Chrome requires explicit VP8 or AV1 preference to reliably support three-layer simulcast. H.264 defaults to SVC or restricts to two layers. Configure codec preferences before the initial offer/answer exchange. Review Media Handling, Codecs & Bandwidth Estimation for Chromium constraint architecture.

Define maxBitrate and scaleResolutionDownBy explicitly per encoding. This prevents Chrome’s auto-scaling from collapsing layers during handshake.

Configuring RTCRtpEncodingParameters

The implementation relies on sender.getParameters() and modifying the encodings array. Chrome expects exactly three objects for low, medium, and high tiers. Each encoding requires rid, active, maxBitrate, scaleResolutionDownBy, and maxFramerate. Proper structuring is critical for Simulcast & SVC Implementation.

Avoid overlapping bitrate ranges. Chrome’s BWE drops the highest layer if network conditions dip below the threshold. Apply parameters via sender.setParameters() immediately after track addition. Execute this before the first frame encodes to prevent InvalidModificationError.

Three-Layer Simulcast Configuration

const sender = pc.getSenders().find(s => s.track.kind === 'video');
const params = sender.getParameters();
params.encodings = [
 { rid: 'low', maxBitrate: 150000, scaleResolutionDownBy: 4.0, maxFramerate: 15 },
 { rid: 'medium', maxBitrate: 500000, scaleResolutionDownBy: 2.0, maxFramerate: 30 },
 { rid: 'high', maxBitrate: 2000000, scaleResolutionDownBy: 1.0, maxFramerate: 30 }
];
await sender.setParameters(params);

Expected Logs:

[INFO] RTCRtpSender::SetParameters: 3 encodings applied.
[TRACE] Simulcast: Layer 'low' active, bitrate=148kbps, res=320x180
[TRACE] Simulcast: Layer 'medium' active, bitrate=492kbps, res=640x360
[TRACE] Simulcast: Layer 'high' active, bitrate=1.8Mbps, res=1280x720

Reproduction Steps:

  1. Initialize RTCPeerConnection with VP8 preferred via setCodecPreferences.
  2. Add video track via addTrack() and capture the sender.
  3. Modify the encodings array with three distinct rid configurations.
  4. Call setParameters() and await resolution.
  5. Open chrome://webrtc-internals to verify three active SSRCs.

Verifying Layer Activation

Validate transmission using chrome://webrtc-internals. Navigate to Stats > VideoSender. Each active layer displays distinct SSRC values and googSimulcast flags.

Monitor the Bytes Sent graph to confirm three parallel streams. A single visible layer indicates an RTCError in the console. Chrome trace logs will explicitly state Simulcast: 3 layers configured upon success.

Handling Congestion Control & Layer Switching

Chrome’s GCC dynamically switches layers based on RTT and packet loss. Implement an application-level debounce before manually toggling active flags. Monitor bytesSent deltas across SSRCs to track bandwidth allocation.

If the medium layer consistently drops, reduce scaleResolutionDownBy for the high layer from 2.0 to 1.5. This eases encoder load during constrained conditions. Manual intervention should only occur during persistent degradation. The congestion estimator automatically promotes or demotes layers otherwise.

Common Mistakes

FAQ

Why does Chrome only show one or two simulcast layers despite configuring three? Chrome’s congestion controller or encoder limits collapse layers if bandwidth drops below the combined threshold. Ensure VP8/AV1 is preferred and verify distinct scaleResolutionDownBy values.

Can I force simulcast over H.264 in Chrome? Chromium prioritizes SVC over simulcast for H.264. Use VP8 or AV1 and configure codec preferences before SDP generation for reliable three-layer output.

How do I debug simulcast layer drops in production? Monitor chrome://webrtc-internals for SSRC-specific bytesSent and googSimulcast flags. Implement logging for setParameters() outcomes and track BWE state via getStats().