Как предотвратить "Требование play() было прервано ошибкой вызова pause()"?

Я сделал сайт, где, если пользователь нажимает, он воспроизводит звук. Чтобы звук не перекрывался, мне пришлось добавить код:

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

Но это вызывает ошибку: The play() request was interrupted by a call to pause()
Подниматься каждый раз, когда звуковое событие запускается сразу после другого триггера. Звук по-прежнему играет нормально, но я хочу, чтобы это сообщение об ошибке постоянно появлялось. Есть идеи?

Ответ 1

Я также недавно столкнулся с этой проблемой - это может быть условие гонки между play() и pause(). Похоже, что есть ссылка на эту проблему, или что-то связанное здесь.

Как указывает @Patrick, pause не возвращает обещание (или что-либо еще), поэтому приведенное выше решение не будет работать. Хотя в MDN нет документов по pause(), в проекте WC3 для Media Elements говорится:

media.pause()

Устанавливает для атрибута paused значение true, при необходимости загружая медиаресурс.

Таким образом, можно также проверить атрибут paused в их обратном вызове тайм-аута.

Основываясь на этом великолепном ответе SO, здесь вы можете проверить, действительно ли видео воспроизводится (или нет), поэтому вы можете безопасно запустить play() без ошибки.

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

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

В противном случае ответ @Patrick должен работать.

Ответ 2

После нескольких часов поисков и работы я нашел идеальное решение.

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

После этого вы можете переключать воспроизведение/паузу так быстро, как сможете, это будет работать правильно.

Ответ 3

Я столкнулся с этой проблемой и имею случай, когда мне нужно было нажать pause(), затем play(), но при использовании pause(). then() Я получаю undefined.

Я обнаружил, что если я начал играть за 150 мс после паузы, он решил проблему. (Надеюсь, Google скоро исправится)

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

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

Ответ 4

попробуйте

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

Ответ 6

Это решение помогло мне:

n.cloneNode(true).play();

Ответ 7

В зависимости от того, насколько сложным вы хотите решение, это может быть полезно:

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

Это немного перебор, но помогает при обработке обещаний в уникальных сценариях.

Ответ 8

Решения, предлагаемые здесь, либо не работали для меня, либо там, где они были большими, поэтому я искал что-то еще и нашел решение, предложенное @dighan на bountysource.com/issues/

Итак, вот код, который решил мою проблему:

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

Он по-прежнему вызывает ошибку в консоли, но по крайней мере воспроизводится видео:)

Ответ 9

Я исправил это с помощью кода ниже:

Когда вы хотите играть, используйте следующее:

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

Ответ 10

Возможно, лучшее решение для этого, как я понял. Spec говорит, как цитируется @JohnnyCoder:

media.pause()

Устанавливает атрибут паузы в значение true, при необходимости загружая медиа-ресурс.

- > Загрузка

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

указывает состояние готовности среды HAVE_ENOUGH_DATA = 4

В основном загружать видео, если он еще не загружен. Упомянутая ошибка возникла для меня, потому что видео не было загружено. Возможно, лучше, чем использовать таймаут.

Ответ 11

удалены все ошибки: (typescript)

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

Ответ 12

С потоковой трансляцией я столкнулся с той же проблемой. и мое исправление - это. Из html видео TAG убедитесь, что удалить "автовоспроизведение" и используйте этот ниже код для воспроизведения.

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

Ответ 13

Chrome возвращает Promise в новейших версиях. В противном случае просто:

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

Ответ 14

У меня такая же проблема, наконец, я решаю:

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

Ответ 15

Этот кусок кода исправлен для меня!

Модифицированный код @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();
                }
            };
        };
       }
      });

Ответ 16

Вот еще одно решение, если причина в том, что ваша загрузка видео очень медленная и видео не буферизовано:

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

Ответ 17

Похоже, что многие программисты столкнулись с этой проблемой. решение должно быть довольно простым. media element возвращает Promise из действий, поэтому

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

должен сделать трюк

Ответ 18

вот решение из блога googler:

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

Ответ 19

Все новые браузеры поддерживают видео для автоматического воспроизведения с отключенным звуком, поэтому, пожалуйста, установите что-то вроде этого

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

URL-адрес видео должен соответствовать статусу SSL, если ваш сайт работает с https, тогда URL-адрес видео также должен быть в https и такой же для HTTP

Ответ 20

Я столкнулся с той же проблемой и разрешил ее, динамически добавляя атрибут autoplay, а не используя play(). Таким образом, браузер решил сыграть, не вбегая в состояние гонки.

Ответ 21

Попытка получить автовоспроизведение видео в цикле, вызвав 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

Ответ 22

Я думаю, они обновили видео 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>

Ответ 23

Когда вы видите ошибку с 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);
});

Ответ 24

Я использовал трюк, чтобы противостоять этой проблеме. Определить глобальную переменную var audio;

и в функции check

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

и в функции останова

audio.pause();
audio = undefined;

так что следующий вызов audio.play, звук будет готов от '0' currentTime

Я использовал

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

но это не сработало. Спасибо.