Search code examples
javascripthtmlhtml5-video

How to detect whether HTML5 video has paused for buffering?


I'm trying to test whether a video is choppy. I have noticed that the pause event is not triggered when the video pauses for buffering. What is the best way to detect whether the video has paused for buffering?


Solution

  • Per the other answers given after this was posted in 2014, you should use the waiting event:

    The waiting event is fired when playback has stopped because of a temporary lack of data.

    Example from MDN:

    const video = document.querySelector("video");
    
    video.addEventListener("waiting", (event) => {
      console.log("Video is waiting for more data.");
    });
    

    Note that if you are working with a particular player (e.g., dash.js or hls.js), these may have their own APIs for tracking state, which may be more expressive than the HTML media element APIs.


    Earlier answer from 2014

    I did this by inspecting the player progress every x milliseconds, e.g. 50. If the player hasn't advanced as much as it was expected to, then we are buffering. This is quite reliable, since I've found that other events such as waiting or stalled are not fired in all cases of the video buffering.

    Note that the interval must be larger than the expected inter-frame difference, but I'm sure that you won't want to be that precise anyway. An estimation of buffering time within ±300ms would still be fine, given that humans most likely cannot perceive differences in that region.

    It is important to check whether the user hasn't actively paused the playback though.

    var checkInterval  = 50.0 // check every 50 ms (do not use lower values)
    var lastPlayPos    = 0
    var currentPlayPos = 0
    var bufferingDetected = false
    var player = document.getElementById('videoPlayer')
    
    setInterval(checkBuffering, checkInterval)
    function checkBuffering() {
        currentPlayPos = player.currentTime
    
        // checking offset should be at most the check interval
        // but allow for some margin
        var offset = (checkInterval - 20) / 1000
    
        // if no buffering is currently detected,
        // and the position does not seem to increase
        // and the player isn't manually paused...
        if (
                !bufferingDetected 
                && currentPlayPos < (lastPlayPos + offset)
                && !player.paused
            ) {
            console.log("buffering")
            bufferingDetected = true
        }
    
        // if we were buffering but the player has advanced,
        // then there is no buffering
        if (
            bufferingDetected 
            && currentPlayPos > (lastPlayPos + offset)
            && !player.paused
            ) {
            console.log("not buffering anymore")
            bufferingDetected = false
        }
        lastPlayPos = currentPlayPos
    }