WebRTC video freezing: causes and how to diagnose it
Why WebRTC video freezes, which getStats metrics show it, and how to tell a network freeze from a decode problem.
During video calls or live streaming, there are times when the video freezes for a few seconds. It might be "stuck" on the last frame and then jump ahead.
This common problem can be analyzed by opening webrtc-internals, and start looking for freezes. Lets see what a video freeze is in WebRTC, what causes it, which getStats() metrics measure it, and how to tell a network freeze apart from other video decode problems.
What a video freeze actually is
A video freeze is a stretch where no new video frames are rendered. The last good frame stays on screen until decoding can resume. WebRTC counts these explicitly: a freeze is registered when the gap between rendered frames crosses a threshold well above the normal frame interval.
Two getStats() metrics measure it directly:
inbound-rtp.freezeCount: how many distinct freezes happened.inbound-rtp.totalFreezesDuration: how much time was spent frozen in total.
To find the cause you also read the frame pipeline: framesReceived, framesDropped, framesDecoded, and keyFramesDecoded.
In a way, video freeze is mostly a more narrow case of packet loss - a single packet lost can cause a whole frame to be marked as lost and ignored by the decoder, which can lead to a cascading effect of following frames that are dropped and not decided due to their dependence on that initial lost packet. This chain of lost frames is what causes a freeze. WebRTC's media resilience mechanisms try to prevent exactly this, but once enough is lost the freeze shows through. Where packet loss indicates a technical problem, video freeze translates it into a visible user problem.
What causes it
In rough order of how often it is the culprit:
- Packet loss on video. Lose enough packets and a frame cannot be assembled, so playback stalls until a full frame arrives again. The most common cause.
- Waiting for a keyframe. After loss, the decoder needs a fresh keyframe to recover. If the sender is slow to produce one, the freeze lasts until it arrives.
- Bandwidth collapse. When the estimated bandwidth drops hard, the sender may pause or slow video, which looks like a freeze on the far end.
- CPU starvation on the receiver. A device that cannot decode fast enough drops frames and stalls, even on a clean network.
- Sender-side encode stalls. If the sender cannot encode fast enough (CPU or capture problems), frames never leave, so the receiver freezes.
How to diagnose it
Read the freeze counters, then read the frame pipeline to find why.
| Metric | Healthy | Trouble |
|---|---|---|
freezeCount |
near zero | rising through the call |
totalFreezesDuration |
negligible | seconds of accumulated freeze |
framesDropped versus framesReceived |
few drops | many frames received but dropped |
keyFramesDecoded |
steady | spikes right after each freeze |
The correlation is what matters:
- Freezes line up with packet loss: the network broke the frames. Treat it as a packet loss problem and see that guide.
- Frozen, then a keyframe decodes, then it recovers: classic post-loss recovery. The freeze length is really keyframe-wait time.
- Frames received but dropped, loss low: the receiver cannot keep up. Look at CPU and decode time, not the network.
- Video frozen but audio fine: the network is carrying audio, so the path is up. This points at video-specific causes: keyframe waits, bandwidth throttling of video, or decode limits.
Do this over time. A single freeze during a Wi-Fi roam is a transient; repeated freezes with rising keyFramesDecoded point at ongoing loss and recovery.
How rtcStats surfaces it
Lining up freeze counters with the frame pipeline and the loss timeline by hand in webrtc-internals is tedious. rtcStats reads the dump for you: it flags each freeze as an Observation, ties it to what packet loss, keyframes, and decode were doing at that moment as a Deduction (network freeze versus a decode stall), and reflects the frozen time in the Experience Score so you can see how much it hurt the call. The AI Summary gives you the one-paragraph version to paste into your bug thread.
Related
- inbound-rtp.freezeCount
- inbound-rtp.totalFreezesDuration
- inbound-rtp.framesDropped
- inbound-rtp.keyFramesDecoded
- WebRTC packet loss
Upload a webrtc-internals or rtcstats dump and rtcStats tells you whether the freeze was the network or the decoder, free.
Was this page helpful?