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:
- Initialize
RTCPeerConnectionwith VP8 preferred viasetCodecPreferences. - Add video track via
addTrack()and capture the sender. - Modify the
encodingsarray with three distinctridconfigurations. - Call
setParameters()and await resolution. - Open
chrome://webrtc-internalsto 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
- Setting
maxBitratevalues too close together, causing BWE to collapse layers. - Forcing three layers on H.264, which Chromium defaults to SVC.
- Calling
setParameters()after the first frame encodes. - Ignoring
scaleResolutionDownBy, leading to CPU spikes and single-layer fallback. - Toggling
activeflags without debouncing, causing rapid switching and packet loss.
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().