Bagaimana mencegah kesalahan "The play () telah terputus oleh panggilan untuk pause ()" error?

107

Saya membuat situs web di mana jika pengguna mengklik, itu memainkan suara. Untuk mencegah suara tumpang tindih, saya harus menambahkan kode:

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

Tapi itu menyebabkan kesalahan: The play() request was interrupted by a call to pause()
Muncul setiap kali peristiwa suara dipicu tepat setelah pemicu lain. Suara masih diputar dengan baik, tetapi saya ingin mencegah pesan kesalahan ini terus-menerus muncul. Ada ide?

Owen M
sumber
apakah itu kesalahan, atau lebih dari sekedar pemberitahuan?
dandavis
Ini adalah kesalahan, ini adalah kesalahan lengkapnya: Tidak tertangkap (dalam janji) DOMException: Permintaan play () diinterupsi oleh panggilan ke pause ().
Owen M
7
ini adalah bug yang lebih baru, jangan khawatir tentang itu: bugs.chromium.org/p/chromium/issues/detail?id=593273
dandavis
3
Perbaikan sederhana untuk ini adalah dengan tidak memanggil putar atau jeda tepat setelah satu sama lain. Gunakan acara media sebagai gantinya untuk menentukan kapan harus menjeda atau memutar. Contoh: onCanPlay(). Semua jawaban ini adalah peretasan kotor.
Martin Dawson
1
Saya memiliki masalah sebaliknya. Saya mencoba untuk n.play() itu n.pause() . Untuk itu, artikel Dasar-Dasar Web ini menjelaskan solusinya. tl; dr:n.play().then(() => { n.pause()})
totymedli

Jawaban:

84

Saya juga mengalami masalah ini baru-baru ini - ini bisa menjadi kondisi balapan antara play()dan pause(). Sepertinya ada referensi ke masalah ini, atau sesuatu yang terkait di sini .

Seperti yang ditunjukkan @Patrick , pausetidak mengembalikan janji (atau apa pun), jadi solusi di atas tidak akan berfungsi. Meskipun MDN tidak memiliki dokumen pause(), dalam draf WC3 untuk Elemen Media , dikatakan:

media.pause ()

Menyetel atribut jeda ke true, memuat sumber daya media jika perlu.

Jadi, seseorang juga dapat memeriksa pausedatribut di callback batas waktunya.

Berdasarkan jawaban SO yang hebat ini , berikut adalah cara Anda dapat memeriksa apakah video (atau tidak) benar-benar diputar, sehingga Anda dapat dengan aman memicu pemutaran () tanpa kesalahan.

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

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

Jika tidak, @Patrick 's jawaban harus bekerja.

JohnnyCoder
sumber
1
Seperti yang dikatakan @ regency-software, metode pause tidak mengembalikan sebuah Promise (tidak ada dokumen tentang .pause ()), tetapi hanya "tidak ditentukan". Jadi solusi ini hanya dapat diterapkan pada kasus play () lalu pause ().
Splact
Terima kasih atas infonya - Saya memperbarui jawaban saya untuk mencerminkan apa yang diposting perangkat lunak @regency, yang benar, dan dia juga memiliki solusi yang berfungsi :-).
JohnnyCoder
bagaimana Anda sampai pada 150ms sebagai waktu tunggu? tampaknya menjadi masalah chrome: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish
Lihat @Regency Software 's jawaban untuk alasan timeout. Saya memperluas jawaban mereka, yang merupakan solusi yang baik. Juga, jawaban saya merujuk pada tautan yang Anda berikan di awal jawaban.
JohnnyCoder
Ini tidak akan berfungsi untuk video streaming. Jika saya telah menginisialisasi video WebRTC, ini masih memberikan pengecualian pada konsol.
Stepan Yakovenko
70

Setelah berjam-jam mencari dan bekerja, saya menemukan solusi yang tepat .

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

Setelah itu, Anda dapat mengaktifkan putar / jeda secepat mungkin, ini akan berfungsi dengan baik .

Nebojsa Sapic
sumber
1
Beginilah cara saya mencapai masalah. Saya merasa ini adalah solusi yang jauh lebih baik daripada mengandalkan waktu tunggu
Malcor
@Malcor Terima kasih, ini akan memperbaiki masalah untuk semua orang
Nebojsa Sapic
Bisakah beberapa orang memberi hadiah pada jawaban ini agar mendapat suara positif lebih cepat?
AddingColor
1
Mengapa tidak ditandai sebagai jawaban yang benar? Jelas ini adalah solusi, bukan peretasan dengan batas waktu.
jeron-diovis
15
Mengapa dua variabel diperlukan? Saya tidak mengatakan ini adalah solusi yang buruk. Hanya mencoba membelai itu.
benevolentprof
20

Saya telah mengalami masalah ini, dan memiliki kasus di mana saya perlu menekan pause () lalu play () tetapi ketika menggunakan pause (). Then () saya tidak terdefinisi.

Saya menemukan bahwa jika saya mulai bermain 150ms setelah jeda itu menyelesaikan masalah. (Semoga Google segera memperbaiki)

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

//Avoid the Promise Error
setTimeout(function () {      
   playerMP3.play();
}, 150);
Patrick
sumber
Jika yang Anda maksud 150ms? Saya mencoba beberapa nilai berbeda, dan menetapkan ini untuk tujuan saya. Saya menargetkan Chrome dan Android dan itu sesuai dengan kebutuhan aplikasi saya. Mungkin bisa lebih rendah.
Patrick
3
jadi nilai itu hampir acak karena tidak terkait dengan hal lain selain impl Anda. terimakasih atas klarifikasinya !
y_nk
Saya ingin tahu apakah Anda menggunakan elemen yang sama untuk memainkan banyak suara? Itu akan menjelaskan masalah muatan; satu suara masih dimuat saat mencoba memutar suara lain melalui elemen yang sama. Penundaan "dapat" menghentikannya meskipun ini merupakan perbaikan yang lamban dan penundaan yang lebih lama / lebih pendek dapat digunakan untuk pengalaman yang lebih baik / terbaik. Menghapus dan membuat ulang elemen dengan cepat telah menjadi SOP saya yang melewatkan sejumlah kebocoran audio / video dan memori.
pohon
1
Sepertinya bug chrome: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish
8
Durasi setTimeout sewenang-wenang tidak boleh digunakan untuk mengatasi kondisi balapan.
Gadget Blaster
5

Cobalah

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

Solusi ini membantu saya:

n.cloneNode(true).play();
Dmitry Kovganov
sumber
2

Bergantung pada seberapa kompleks Anda menginginkan solusi Anda, ini mungkin berguna:

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

Ini sedikit berlebihan, tetapi membantu saat menangani Janji dalam skenario unik.

Krayon Biru
sumber
2

Solusi yang diusulkan di sini tidak berhasil untuk saya atau di mana harus besar, jadi saya mencari sesuatu yang lain dan menemukan solusi yang diusulkan oleh @dighan di bountysource.com/issues/

Jadi, inilah kode yang memecahkan masalah saya:

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

Itu masih membuat kesalahan ke konsol, tetapi setidaknya video diputar :)

Sharpey
sumber
1

Mungkin solusi yang lebih baik untuk ini seperti yang saya pikirkan. Spec mengatakan seperti yang dikutip dari @JohnnyCoder:

media.pause ()

Menyetel atribut jeda ke true, memuat sumber daya media jika perlu.

-> memuatnya

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

menunjukkan status kesiapan media HAVE_ENOUGH_DATA = 4

Pada dasarnya hanya memuat video jika belum dimuat. Kesalahan yang disebutkan terjadi pada saya, karena video tidak dimuat. Mungkin lebih baik daripada menggunakan waktu tunggu.

Christoph Eberl
sumber
1

menghapus semua kesalahan: (skrip ketikan)

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

Dengan streaming langsung, saya menghadapi masalah yang sama. dan perbaikan saya adalah ini. Dari TAG video html pastikan untuk menghapus "putar otomatis" dan gunakan kode di bawah ini untuk memutar.

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;
                    }
                }
            });
        }
Solusi Neutro
sumber
1
Solusi bagus !!
Junaid Mukhtar
1

Chrome mengembalikan Janji dalam versi terbaru. Jika tidak, cukup:

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

Saya memiliki masalah yang sama, akhirnya saya menyelesaikan dengan:

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

Potongan kode ini diperbaiki untuk saya!

Kode @JohnnyCoder yang dimodifikasi

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();
                }
            };
        };
       }
      });
Eliotjse
sumber
1

Saya telah memperbaikinya dengan beberapa kode di bawah ini:

Saat Anda ingin bermain, gunakan yang berikut ini:

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

Begitu pula saat Anda ingin menjeda:

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

video_play.on('canplay', function() {
  video_play.trigger('pause');
});
Duc Nguyen
sumber
0

Berikut adalah solusi lain jika alasannya adalah unduhan video Anda sangat lambat dan video tidak buffer:

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

Taysky
sumber
0

Sepertinya banyak programmer yang mengalami masalah ini. solusinya harus cukup sederhana. elemen media kembali Promisedari tindakan jadi

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

harus melakukan triknya

pery mimon
sumber
0

berikut adalah solusi dari blog 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)
}
stackFish
sumber
0

Semua video dukungan browser baru untuk diputar otomatis dengan hanya dibisukan jadi tolong masukkan Sesuatu seperti ini

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

URL video harus sesuai dengan status SSL jika situs Anda berjalan dengan https maka URL video juga harus dalam https dan sama untuk HTTP

Shobhit Verma
sumber
0

Solusi terbersih dan paling sederhana :

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

Alasan satu - menelepon jeda tanpa menunggu janji permainan diselesaikan

terlalu banyak jawaban untuk skenario ini, jadi saya hanya akan merujuk ke dokumen terbaik untuk masalah itu:

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

Alasan kedua - memanggil putar saat tab tidak fokus

Dalam hal ini, browser dapat menginterupsi playdengan memanggilpause saat tab tidak fokus. untuk menghemat sumber daya untuk tab aktif.

Jadi Anda bisa menunggu tab difokuskan sebelum memanggil putar:


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();
jony89
sumber
-1

Saya mengalami masalah yang sama dan menyelesaikannya dengan menambahkan autoplayatribut secara dinamis daripada menggunakan play(). Dengan begitu browser dipikir untuk bermain tanpa mengalami kondisi balapan.

Jannis Hell
sumber
-1

Mencoba memutar ulang video secara otomatis dengan memanggilnya play()setelah berakhir, solusi batas waktu tidak berhasil untuk saya (betapapun lama waktu tunggu tersebut).

Tetapi saya menemukan bahwa dengan mengkloning / mengganti video dengan jQuery ketika berakhir, itu akan berputar dengan benar.

Sebagai contoh:

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

dan

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

Saya menggunakan Chrome 54.0.2840.59 (64-bit) / OS X 10.11.6

Silvain
sumber
-1

Saya pikir mereka memperbarui video html5 dan menghentikan beberapa codec. Ini berhasil untuk saya setelah menghapus codec.

Pada contoh di bawah ini:

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

Amr
sumber
-1

Ketika Anda melihat kesalahan dengan Uncaught (in promise)Ini berarti Anda harus menangani janji dengan .catch()dalam kasus ini, .play()mengembalikan sebuah janji. Anda dapat memutuskan apakah Anda ingin memasukkan pesan, menjalankan beberapa kode, atau tidak melakukan apa-apa, tetapi selama Anda memiliki .catch()kesalahan itu akan hilang.

var n = new Audio();
n.pause();
n.currentTime = 0;
n.play().catch(function(e) {
  // console.log('There was an error', e);
});
seantomburke
sumber
itu tidak mengembalikan janji
Martin Dawson
@MartinMazzaDawson Itu mengembalikan janji. Jika Anda melihat komentar klarifikasi xxx dalam pertanyaan dia mengatakan "Ini adalah kesalahan, inilah kesalahan lengkapnya: Tidak tertangkap (dalam janji) DOMException: Permintaan play () terganggu oleh panggilan untuk jeda ()."
seantomburke
-5

Saya telah menggunakan trik untuk mengatasi masalah ini. Tentukan audio var variabel global;

dan di pemeriksaan fungsi

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

dan di fungsi stop

audio.pause();
audio = undefined;

jadi panggilan berikutnya audio.play , audio akan siap dari '0' currentTime

Saya dulu

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

tapi tidak berhasil. Terima kasih.

Gippy Aulakh
sumber