[javascript] How to prevent "The play() request was interrupted by a call to pause()" error?

I made a website where if the user clicks, it plays a sound. To prevent the sound from overlapping, I had to add the code:

n.pause();
n.currentTime = 0;
n.play();

But that causes the error: The play() request was interrupted by a call to pause()
To come up each time the sound event is triggered right after another trigger. The sounds still plays fine, but I want to prevent this error message constantly popping up. Any ideas?

This question is related to javascript html google-chrome audio

The answer is


The cleanest and simplest solution:

var p = video.play();
if (p !== undefined) p.catch(function(){});

I have hit this issue, and have a case where I needed to hit pause() then play() but when using pause().then() I get undefined.

I found that if I started play 150ms after pause it resolved the issue. (Hopefully Google fixes soon)

playerMP3.volume = 0;
playerMP3.pause();

//Avoid the Promise Error
setTimeout(function () {      
   playerMP3.play();
}, 150);

here is a solution from googler blog:

var video = document.getElementById('#video')
var promise = video.play()
//chrome version 53+
if(promise){
    promise.then(_=>{
        video.pause()
    })
}else{
    video.addEventListener('canplaythrough', _=>{
        video.pause()
    }, false)
}

All new browser support video to be auto-played with being muted only so please put Something like the this

<video autoplay muted="muted" loop id="myVideo">
  <source src="https://w.r.glob.net/Coastline-3581.mp4" type="video/mp4">
</video>

URL of video should match the SSL status if your site is running with https then video URL should also in https and same for HTTP


I've fixed it with some code bellow:

When you want play, use the following:

var video_play = $('#video-play');
video_play.on('canplay', function() {
 video_play.trigger('play');
});

Similarly, when you want pause:

var video_play = $('#video-play');
video_play.trigger('pause');

video_play.on('canplay', function() {
  video_play.trigger('pause');
});

Reason one - calling pause without waiting for play promise to resolve

too many answer fo this scenario, so I will just refer to the best doc for that issue:

https://developers.google.com/web/updates/2017/06/play-request-was-interrupted

Reason two - calling play when the tab is not focused

In this case, the browser could interrupt the play by calling pause when the tab is not focus. in order to save resources for the active tab.

So you could just wait for the tab to be focused before calling play:


async function waitForTabFocus() {
  return new Promise((resolve, reject) => {
    const onFocus = () => { resolve(); window.removeEventListener('focus', onFocus) };
    window.addEventListener('focus', onFocus)
  })
}
if (!document.hasFocus()) await this.waitForTabFocus();
videoEl.play();

Solutions proposed here either didn't work for me or where to large, so I was looking for something else and found the solution proposed by @dighan on bountysource.com/issues/

So here is the code that solved my problem:

var media = document.getElementById("YourVideo");
const playPromise = media.play();
if (playPromise !== null){
    playPromise.catch(() => { media.play(); })
}

It still throws an error into console, but at least the video is playing :)


Maybe a better solution for this as I figured out. Spec says as cited from @JohnnyCoder :

media.pause()

Sets the paused attribute to true, loading the media resource if necessary.

--> loading it

if (videoEl.readyState !== 4) {
    videoEl.load();
}
videoEl.play();

indicates the readiness state of the media HAVE_ENOUGH_DATA = 4

Basically only load the video if it is not already loaded. Mentioned error occurred for me, because video was not loaded. Maybe better than using a timeout.


This solution helped me:

n.cloneNode(true).play();

With live streaming i was facing the same issue. and my fix is this. From html video TAG make sure to remove "autoplay" and use this below code to play.

if (Hls.isSupported()) {
            var video = document.getElementById('pgVideo');
            var hls = new Hls();
            hls.detachMedia();
            hls.loadSource('http://wpc.1445X.deltacdn.net/801885C/lft/apple/TSONY.m3u8');
            hls.attachMedia(video);
            hls.on(Hls.Events.MANIFEST_PARSED, function () {
                video.play();
            });
            hls.on(Hls.Events.ERROR, function (event, data) {
                if (data.fatal) {
                    switch (data.type) {
                        case Hls.ErrorTypes.NETWORK_ERROR:
                            // when try to recover network error
                            console.log("fatal network error encountered, try to recover");
                            hls.startLoad();
                            break;
                        case Hls.ErrorTypes.MEDIA_ERROR:
                            console.log("fatal media error encountered, try to recover");
                            hls.recoverMediaError();
                            break;
                        default:
                            // when cannot recover
                            hls.destroy();
                            break;
                    }
                }
            });
        }

Trying to get an autoplaying video to loop by calling play() when it ends, the timeout workaround did not work for me (however long the timeout is).

But I discovered that by cloning/replacing the video with jQuery when it ended, it would loop properly.

For example:

<div class="container">
  <video autoplay>
    <source src="video.mp4" type="video/mp4">
  </video>
</div>

and

$(document).ready(function(){
  function bindReplay($video) {
    $video.on('ended', function(e){
      $video.remove();
      $video = $video.clone();
      bindReplay($video);
      $('.container').append($video);
    });
  }
  var $video = $('.container video');
  bindReplay($video);
});

I'm using Chrome 54.0.2840.59 (64-bit) / OS X 10.11.6


I ran into the same issue and resolved it by dynamically adding the autoplay attribute rather than using play(). That way the browser figured out to play without running into the race condition.


I have the same issue, finally i solve by:

video.src = 'xxxxx';
video.load();
setTimeout(function() {
  video.play();
}, 0);

This piece of code fixed for me!

Modified code of @JohnnyCoder

HTML:

 <video id="captureVideoId" muted width="1280" height="768"></video>
                <video controls id="recordedVideoId" muted width="1280" 
 style="display:none;" height="768"></video>

JS:

  var recordedVideo = document.querySelector('video#recordedVideoId');
  var superBuffer = new Blob(recordedBlobs, { type: 'video/webm' });
  recordedVideo.src = window.URL.createObjectURL(superBuffer);
  // workaround for non-seekable video taken from
  // https://bugs.chromium.org/p/chromium/issues/detail?id=642012#c23
  recordedVideo.addEventListener('loadedmetadata', function () {
    if (recordedVideo.duration === Infinity) {
        recordedVideo.currentTime = 1e101;
        recordedVideo.ontimeupdate = function () {
            recordedVideo.currentTime = 0;
            recordedVideo.ontimeupdate = function () {
                delete recordedVideo.ontimeupdate;
                var isPlaying = recordedVideo.currentTime > 0 && 
     !recordedVideo.paused && !recordedVideo.ended && 
      recordedVideo.readyState > 2;
                if (isPlaying) {
                    recordedVideo.play();
                }
            };
        };
       }
      });

I've just published an article about this exact issue at https://developers.google.com/web/updates/2017/06/play-request-was-interrupted that tells you exactly what is happening and how to fix it.


I have used a trick to counter this issue. Define a global variable var audio;

and in the function check

if(audio === undefined)
{
   audio = new Audio(url);
}

and in the stop function

audio.pause();
audio = undefined;

so the next call of audio.play, audio will be ready from '0' currentTime

I used

audio.pause();
audio.currentTime =0.0; 

but it didn't work. Thanks.


Here is another solution if the reason is that your video download is super slow and the video hasn't buffered:

if (videoElement.state.paused) { videoElement.play(); } else if (!isNaN(videoElement.state.duration)) { videoElement.pause(); }


I think they updated the html5 video and deprecated some codecs. It worked for me after removing the codecs.

In the below example:

_x000D_
_x000D_
<video>_x000D_
    <source src="sample-clip.mp4" type="video/mp4; codecs='avc1.42E01E, mp4a.40.2'">_x000D_
    <source src="sample-clip.webm" type="video/webm; codecs='vp8, vorbis'"> _x000D_
</video>_x000D_
_x000D_
    must be changed to_x000D_
_x000D_
<video>_x000D_
    <source src="sample-clip.mp4" type="video/mp4">_x000D_
    <source src="sample-clip.webm" type="video/webm">_x000D_
</video>
_x000D_
_x000D_
_x000D_


Depending on how complex you want your solution, this may be useful:

var currentPromise=false;    //Keeps track of active Promise

function playAudio(n){
    if(!currentPromise){    //normal behavior
        n.pause();
        n.currentTime = 0;
        currentPromise = n.play();    //Calls play. Will store a Promise object in newer versions of chrome;
                                      //stores undefined in other browsers
        if(currentPromise){    //Promise exists
            currentPromise.then(function(){ //handle Promise completion
                promiseComplete(n);
            });
        }
    }else{    //Wait for promise to complete
        //Store additional information to be called
        currentPromise.calledAgain = true;
    }
}

function promiseComplete(n){
    var callAgain = currentPromise.calledAgain;    //get stored information
    currentPromise = false;    //reset currentPromise variable
    if(callAgain){
        playAudio(n);
    }
}

This is a bit overkill, but helps when handling a Promise in unique scenarios.


Chrome returns a Promise in newest versions. Otherwise, simply:

        n.pause();
        n.currentTime = 0;
        setTimeout(function() {n.play()}, 0);

When you see an error with Uncaught (in promise) This just means that you need to handle the promise with a .catch() In this case, .play() returns a promise. You can decide if you want to log a message, run some code, or do nothing, but as long as you have the .catch() the error will go away.

var n = new Audio();
n.pause();
n.currentTime = 0;
n.play().catch(function(e) {
  // console.log('There was an error', e);
});

It looks like a lot of programmers encountered this problem. a solution should be quite simple. media element return Promise from actions so

n.pause().then(function(){
    n.currentTime = 0;
    n.play();
})

should do the trick


removed all errors: (typescript)

audio.addEventListener('canplay', () => {
    audio.play();
    audio.pause();
    audio.removeEventListener('canplay');
}); 

try it

n.pause();
n.currentTime = 0;
var nopromise = {
   catch : new Function()
};
(n.play() || nopromise).catch(function(){}); ;

After hours of seaching and working, i found perfect solution.

// Initializing values
var isPlaying = true;

// On video playing toggle values
video.onplaying = function() {
    isPlaying = true;
};

// On video pause toggle values
video.onpause = function() {
    isPlaying = false;
};

// Play video function
function playVid() {      
    if (video.paused && !isPlaying) {
        video.play();
    }
} 

// Pause video function
function pauseVid() {     
    if (!video.paused && isPlaying) {
        video.pause();
    }
}

After that, you can toggle play/pause as fast as you can, it will work properly.


Examples related to javascript

need to add a class to an element How to make a variable accessible outside a function? Hide Signs that Meteor.js was Used How to create a showdown.js markdown extension Please help me convert this script to a simple image slider Highlight Anchor Links when user manually scrolls? Summing radio input values How to execute an action before close metro app WinJS javascript, for loop defines a dynamic variable name Getting all files in directory with ajax

Examples related to html

Embed ruby within URL : Middleman Blog Please help me convert this script to a simple image slider Generating a list of pages (not posts) without the index file Why there is this "clear" class before footer? Is it possible to change the content HTML5 alert messages? Getting all files in directory with ajax DevTools failed to load SourceMap: Could not load content for chrome-extension How to set width of mat-table column in angular? How to open a link in new tab using angular? ERROR Error: Uncaught (in promise), Cannot match any routes. URL Segment

Examples related to google-chrome

SessionNotCreatedException: Message: session not created: This version of ChromeDriver only supports Chrome version 81 SameSite warning Chrome 77 What's the net::ERR_HTTP2_PROTOCOL_ERROR about? session not created: This version of ChromeDriver only supports Chrome version 74 error with ChromeDriver Chrome using Selenium Jupyter Notebook not saving: '_xsrf' argument missing from post How to fix 'Unchecked runtime.lastError: The message port closed before a response was received' chrome issue? Selenium: WebDriverException:Chrome failed to start: crashed as google-chrome is no longer running so ChromeDriver is assuming that Chrome has crashed WebDriverException: unknown error: DevToolsActivePort file doesn't exist while trying to initiate Chrome Browser How to make audio autoplay on chrome How to handle "Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first." on Desktop with Chrome 66?

Examples related to audio

How to prevent "The play() request was interrupted by a call to pause()" error? Creating and playing a sound in swift How to play or open *.mp3 or *.wav sound file in c++ program? How to playback MKV video in web browser? Play audio as microphone input HTML embed autoplay="false", but still plays automatically Autoplay an audio with HTML5 embed tag while the player is invisible Playing mp3 song on python Javascript Audio Play on click Play sound on button click android