如何防止“play()请求被暂停()调用中断”错误?

时间:2016-04-22 20:55:31

标签: javascript html google-chrome audio

我创建了一个网站,如果用户点击,它会发出声音。为防止声音重叠,我不得不添加代码:

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

但是这会导致错误: The play() request was interrupted by a call to pause()
每次触发声音事件后立即启动。声音仍然很好,但我想防止这个错误信息不断弹出。有什么想法吗?

27 个答案:

答案 0 :(得分:72)

我最近也遇到过这个问题 - 这可能是play()pause()之间的竞争条件。看起来有一个对此问题的引用,或与here相关的内容。

正如@Patrick指出的那样,pause不会返回承诺(或任何内容),因此上述解决方案无法正常工作。虽然MDN在pause()上没有文档,但在WC3 draft for Media Elements中,它说:

  

media.pause()

     

将paused属性设置为true,并在必要时加载媒体资源。

因此,人们也可以检查超时回调中的paused属性。

基于this great SO answer,您可以通过以下方式检查视频是否(或者不是)正在播放,因此您可以安全地触发播放()而不会出现错误。

var isPlaying = video.currentTime > 0 && !video.paused && !video.ended 
    && video.readyState > 2;

if (!isPlaying) {
  video.play();
}

否则,@Patrick' answer应该有效。

答案 1 :(得分:60)

经过几个小时的搜索和工作,我找到了完美的 解决方案

// 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();
    }
}

之后,您可以尽快切换 播放/暂停 它将正常运作

答案 2 :(得分:18)

我遇到了这个问题,有一个案例我需要点击pause()然后播放()但是当使用pause()时那么()我得到了未定义。

我发现如果我在暂停后开始播放150毫秒就解决了这个问题。 (希望Google尽快修复)

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

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

答案 3 :(得分:5)

试试吧

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

答案 4 :(得分:4)

我刚刚在https://developers.google.com/web/updates/2017/06/play-request-was-interrupted发布了一篇关于这个确切问题的文章,它可以准确地告诉您发生了什么以及如何解决这个问题

答案 5 :(得分:3)

这个解决方案帮助了我:

n.cloneNode(true).play();

答案 6 :(得分:2)

根据您希望解决方案的复杂程度,这可能很有用:

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);
    }
}

这有点矫枉过正,但在处理独特场景中的Promise时会有所帮助。

答案 7 :(得分:2)

这里提出的解决方案要么对我不起作用,要么在哪里工作, 所以我正在寻找其他的东西,并找到了@dighan在bountysource.com/issues/

上提出的解决方案

所以这是解决我问题的代码:

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

它仍会向控制台抛出错误,但至少视频正在播放:)

答案 8 :(得分:1)

我用一些代码修正了它:

如果您想玩,请使用以下内容:

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

同样,当你想要暂停时:

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

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

答案 9 :(得分:1)

这段代码为我修好了!

@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();
                }
            };
        };
       }
      });

答案 10 :(得分:1)

正如我所知,也许是一个更好的解决方案。 规范说@JohnnyCoder引用:

  

media.pause()

     

将paused属性设置为true,并在必要时加载媒体资源。

- &GT;加载它

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

表示媒体的准备状态 HAVE_ENOUGH_DATA = 4

基本上只加载视频(如果尚未加载)。我提到错误,因为未加载视频。 也许比使用超时更好。

答案 11 :(得分:1)

我有同样的问题,最后我解决了:

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

答案 12 :(得分:1)

删除了所有错误:(打字稿)

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

答案 13 :(得分:1)

通过直播,我遇到了同样的问题。我的解决方法就是这个。 从html视频TAG确保删除&#34;自动播放&#34; 并使用下面的代码来播放。

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;
                    }
                }
            });
        }

答案 14 :(得分:1)

Chrome会在最新版本中返回Promise。 否则,只需:

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

答案 15 :(得分:0)

原因之一-无需等待播放承诺解决就叫暂停

在这种情况下,答案太多,因此,我将仅参考针对该问题的最佳文档:

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

原因之二-在标签未聚焦时调用播放

在这种情况下,浏览器可以中断process.on('unhandledRejection', error => { if (error.code === "ENOTFOUND") { console.log ("No internet connection")} if (error.code === "ECONNREFUSED") { console.log ("Connection refused")} //console.log('Unhandled promise rejection:', error.code); }); 通过调用play当凸片不聚焦。为了节省活动标签的资源。

因此,您可以在调用play之前等待标签集中显示

pause

async function waitForTabFocus() {
  return new Promise((resolve, reject) => {
    const onFocus = () => { resolve(); window.removeEventListener('focus', onFocus) };
    window.addEventListener('focus', onFocus)
  })
}

答案 16 :(得分:0)

最干净的和最简单的解决方案:

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

答案 17 :(得分:0)

所有新的浏览器支持的视频都只能在静音的情况下自动播放,因此请放置类似这样的内容

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

如果您的网站使用https运行,则视频URL应与SSL状态匹配,然后视频URL也应为https且与HTTP相同

答案 18 :(得分:0)

我有类似的问题,我认为做这样的事情最简单:

started

无论视频是否正在播放,视频最后都会无一例外地暂停,然后归零重新播放。

即使视频已经在播放,调用 play() 也能正常工作,它会按预期返回承诺。

答案 19 :(得分:0)

这是来自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)
}

答案 20 :(得分:0)

看起来很多程序员都遇到过这个问题。 解决方案应该非常简单。媒体元素从操作返回Promise

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

应该做的伎俩

答案 21 :(得分:0)

如果原因是您的视频下载速度非常慢并且视频没有缓冲,那么这是另一种解决方案:

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

答案 22 :(得分:-1)

当您看到Uncaught (in promise)出现错误时这意味着您需要使用.catch()来处理承诺。在这种情况下,.play()会返回一个承诺。您可以决定是否要记录消息,运行某些代码或不执行任何操作,但只要您拥有.catch(),错误就会消失。

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

答案 23 :(得分:-1)

我认为他们更新了html5视频并弃用了一些编解码器。 删除编解码器后,它对我有用。

在下面的示例中:

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

    must be changed to

<video>
    <source src="sample-clip.mp4" type="video/mp4">
    <source src="sample-clip.webm" type="video/webm">
</video>

答案 24 :(得分:-1)

尝试通过在play()结束时调用自动播放视频来循环,超时解决方法对我来说不起作用(无论多长时间都是如此)。

但我发现通过jQuery在结束时克隆/替换视频,它会正常循环。

例如:

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

$(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);
});

我正在使用Chrome 54.0.2840.59(64位)/ OS X 10.11.6

答案 25 :(得分:-1)

我遇到了同样的问题并通过动态添加autoplay属性而非使用play()来解决此问题。这样浏览器可以在没有遇到竞争条件的情况下发挥作用。

答案 26 :(得分:-5)

我用了一个技巧来解决这个问题。 定义全局变量var audio;

并在功能检查中

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

和停止功能

audio.pause();
audio = undefined;

所以下一次调用audio.play,音频将从'0'urrentTime

准备好

我用过

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

但它不起作用。 感谢。