Wie kann verhindert werden, dass die Anforderung "play () durch einen Aufruf von pause () unterbrochen wurde"?

107

Ich habe eine Website erstellt, auf der, wenn der Benutzer klickt, ein Ton abgespielt wird. Um zu verhindern, dass sich der Ton überschneidet, musste ich den folgenden Code hinzufügen:

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

Dies führt jedoch zu dem Fehler: The play() request was interrupted by a call to pause()
Wird jedes Mal angezeigt, wenn das Soundereignis direkt nach einem anderen Trigger ausgelöst wird. Die Sounds spielen immer noch gut, aber ich möchte verhindern, dass diese Fehlermeldung ständig auftaucht. Irgendwelche Ideen?

Owen M.
quelle
Ist es ein Fehler oder eher ein Hinweis?
Dandavis
Es ist ein Fehler, hier ist der vollständige Fehler: Nicht erfasst (im Versprechen) DOMException: Die play () -Anforderung wurde durch einen Aufruf von pause () unterbrochen.
Owen M
7
Es ist ein neuerer Fehler, keine Sorge: bugs.chromium.org/p/chromium/issues/detail?id=593273
Dandavis
3
Die einfache Lösung hierfür besteht darin, die Wiedergabe nicht direkt nacheinander aufzurufen oder anzuhalten. Verwenden Sie stattdessen die Medienereignisse, um zu bestimmen, wann angehalten oder abgespielt werden soll. Beispiel : onCanPlay(). Alle diese Antworten sind schmutzige Hacks.
Martin Dawson
1
Ich hatte das gegenteilige Problem. Ich habe es n.play() dann versucht n.pause(). Zu diesem Zweck beschreibt dieser Artikel zu Web Fundamentals die Lösung. tl; dr:n.play().then(() => { n.pause()})
totymedli

Antworten:

84

Ich bin auch kürzlich auf dieses Problem gestoßen - dies könnte eine Rennbedingung zwischen play()und sein pause(). Es sieht so aus, als ob es einen Verweis auf dieses Problem gibt oder etwas, das hier verwandt ist .

Wie @Patrick hervorhebt , pausegibt es kein Versprechen (oder irgendetwas) zurück, sodass die oben genannte Lösung nicht funktioniert. Während MDN keine Dokumente enthält pause(), heißt es im WC3-Entwurf für Medienelemente :

media.pause ()

Setzt das pausierte Attribut auf true und lädt bei Bedarf die Medienressource.

Man könnte also auch das pausedAttribut in ihrem Timeout-Rückruf überprüfen .

Basierend auf dieser großartigen SO-Antwort können Sie auf folgende Weise überprüfen, ob das Video wirklich abgespielt wird (oder nicht), sodass Sie eine Wiedergabe () ohne Fehler sicher auslösen können.

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

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

Andernfalls sollte die Antwort von @Patrick funktionieren.

JohnnyCoder
quelle
1
Wie @ regency-software sagt, gibt die pause-Methode kein Versprechen zurück (es gibt keine Dokumente in .pause ()), sondern nur "undefiniert". Diese Lösung kann also nur in den Fällen play () und dann pause () angewendet werden.
Splact
Vielen Dank für die Info - Ich habe meine Antwort aktualisiert, um zu reflektieren, was @ regency-Software gepostet hat, was korrekt war, und er hatte auch eine funktionierende Lösung :-).
JohnnyCoder
Wie sind Sie auf 150 ms als Wartezeit gekommen? scheint ein Chrome-Problem zu sein: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish
Siehe @Regency Software ‚s Antwort für den Timeout Grund. Ich habe ihre Antwort erweitert, was eine gute Lösung war. Außerdem verweist meine Antwort auf den Link, den Sie zu Beginn der Antwort angegeben haben.
JohnnyCoder
Dies würde beim Streaming von Videos nicht funktionieren. Wenn ich WebRTC-Video initialisiert habe, gibt dies immer noch eine Ausnahme für die Konsole.
Stepan Yakovenko
70

Nach stundenlangem Suchen und Arbeiten fand ich die perfekte Lösung .

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

Danach können Sie die Wiedergabe / Pause so schnell wie möglich umschalten, es funktioniert ordnungsgemäß .

Nebojsa Sapic
quelle
1
So habe ich das Problem erreicht. Ich denke, dies ist eine viel bessere Lösung, als sich auf eine Auszeit zu verlassen
Malcor
@ Malcor Vielen Dank, dies wird das Problem für alle beheben
Nebojsa Sapic
Könnten einige bitte ein Kopfgeld auf diese Antwort setzen, um sie schneller zu bewerten?
Hinzufügen von Farbe
1
Warum ist es nicht als richtige Antwort markiert? Dies ist definitiv eine Lösung, kein Hack mit Timeouts.
Jeron-Diovis
15
Warum sind zwei Variablen notwendig? Ich sage nicht, dass dies eine schlechte Lösung ist. Ich versuche nur, es zu groken.
Wohlwollender
20

Ich bin auf dieses Problem gestoßen und habe einen Fall, in dem ich pause () und dann play () drücken musste, aber bei Verwendung von pause (). Then () werde ich undefiniert.

Ich stellte fest, dass das Problem behoben wurde, wenn ich 150 ms nach der Pause mit dem Spielen begann. (Hoffentlich behebt Google bald)

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

//Avoid the Promise Error
setTimeout(function () {      
   playerMP3.play();
}, 150);
Patrick
quelle
Wenn du die 150ms meinst? Ich habe ein paar verschiedene Werte ausprobiert und mich für meinen Zweck darauf festgelegt. Ich habe auf Chrome und Android abgezielt und es entsprach den Anforderungen meiner App. Es kann niedriger sein.
Patrick
3
Es ist also ein fast zufälliger Wert, da er sich auf nichts anderes als auf Ihr Gerät bezieht. Danke für die Klarstellung !
y_nk
Ich bin gespannt, ob Sie dasselbe Element verwenden, um mehrere Sounds abzuspielen. Das würde das Lastproblem erklären; Ein Sound wird noch geladen, während versucht wird, einen anderen Sound über dasselbe Element abzuspielen. Eine Verzögerung "könnte" es stoppen, obwohl es eine umständliche Lösung ist und längere / kürzere Verzögerungen für eine bessere / beste Erfahrung verwendet werden könnten. Das sofortige Löschen und Wiederherstellen von Elementen war meine SOP, die eine Reihe von Audio- / Video- und Speicherlecks überspringt.
Baum
1
sieht aus wie ein Chrome-Bug: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish
8
Beliebige setTimeout-Dauern sollten nicht zur Lösung von Rennbedingungen verwendet werden.
Gadget Blaster
5

Versuch es

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

Diese Lösung hat mir geholfen:

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

Je nachdem, wie komplex Ihre Lösung sein soll, kann dies hilfreich sein:

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

Dies ist ein bisschen übertrieben, hilft aber bei der Behandlung eines Versprechens in einzigartigen Szenarien.

Der blaue Wachsmalstift
quelle
2

Die hier vorgeschlagenen Lösungen funktionierten entweder nicht für mich oder waren zu groß, also suchte ich nach etwas anderem und fand die von @dighan vorgeschlagene Lösung auf bountysource.com/issues/

Hier ist der Code, der mein Problem gelöst hat:

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

Es wird immer noch ein Fehler in die Konsole geworfen, aber zumindest wird das Video abgespielt :)

Sharpey
quelle
1

Vielleicht eine bessere Lösung dafür, wie ich herausgefunden habe. Spec sagt, wie aus @JohnnyCoder zitiert:

media.pause ()

Setzt das pausierte Attribut auf true und lädt bei Bedarf die Medienressource.

-> Laden

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

gibt den Bereitschaftszustand des Mediums an HAVE_ENOUGH_DATA = 4

Laden Sie das Video grundsätzlich nur, wenn es noch nicht geladen ist. Der erwähnte Fehler ist bei mir aufgetreten, weil das Video nicht geladen wurde. Vielleicht besser als eine Auszeit.

Christoph Eberl
quelle
1

Alle Fehler entfernt: (Typoskript)

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

Beim Live-Streaming stand ich vor dem gleichen Problem. und mein Fix ist das. Stellen Sie im HTML-Video-TAG sicher , dass Sie "Autoplay" entfernen und den folgenden Code zum Abspielen verwenden.

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;
                    }
                }
            });
        }
Neutro-Lösungen
quelle
1
Tolle Lösung !!
Junaid Mukhtar
1

Chrome gibt in den neuesten Versionen ein Versprechen zurück. Ansonsten einfach:

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

Ich habe das gleiche Problem, schließlich löse ich durch:

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

Dieser Code wurde für mich repariert!

Geänderter Code von @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();
                }
            };
        };
       }
      });
Eliotjse
quelle
1

Ich habe es mit einem Code unten behoben:

Wenn Sie spielen möchten, verwenden Sie Folgendes:

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

Ebenso, wenn Sie eine Pause wünschen:

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

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

Hier ist eine andere Lösung, wenn der Grund dafür ist, dass Ihr Video-Download sehr langsam ist und das Video nicht gepuffert hat:

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

Taysky
quelle
0

Es sieht so aus, als ob viele Programmierer auf dieses Problem gestoßen sind. Eine Lösung sollte recht einfach sein. Medienelement Rückkehr Promisevon Aktionen so

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

sollte den Trick machen

pery mimon
quelle
0

hier ist eine lösung von 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)
}
stackFish
quelle
0

Alle neuen Browser-Support-Videos werden automatisch abgespielt und nur stummgeschaltet. Bitte geben Sie so etwas an

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

Die URL des Videos sollte mit dem SSL-Status übereinstimmen, wenn Ihre Site mit https ausgeführt wird. Die Video-URL sollte auch in https und für HTTP gleich sein

Shobhit Verma
quelle
0

Die sauberste und einfachste Lösung:

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

Grund eins - Pause anrufen, ohne auf das Spielversprechen zu warten

Zu viele Antworten auf dieses Szenario, daher beziehe ich mich auf das beste Dokument für dieses Problem:

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

Grund zwei - Aufruf des Spiels, wenn die Registerkarte nicht fokussiert ist

In diesem Fall könnte der Browser das playdurch Aufrufen unterbrechenpause wenn die Registerkarte nicht fokussiert ist. um Ressourcen für die aktive Registerkarte zu sparen.

Sie können also einfach warten, bis der Tab fokussiert ist, bevor Sie play aufrufen:


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

Ich bin auf dasselbe Problem gestoßen und habe es behoben, indem ich das autoplayAttribut dynamisch hinzugefügt habe , anstatt es zu verwenden play(). Auf diese Weise stellte der Browser fest, dass er spielen konnte, ohne in den Rennzustand zu geraten.

Jannis Hölle
quelle
-1

Beim Versuch, ein Video mit automatischer Wiedergabe durch Aufrufen zu einer Schleife zu bringen, play()wenn es beendet wird, hat die Timeout-Problemumgehung bei mir nicht funktioniert (wie lange das Timeout auch ist).

Aber ich habe festgestellt, dass durch das Klonen / Ersetzen des Videos durch jQuery am Ende eine ordnungsgemäße Schleife ausgeführt wird.

Beispielsweise:

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

und

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

Ich verwende Chrome 54.0.2840.59 (64-Bit) / OS X 10.11.6

Silvain
quelle
-1

Ich denke, sie haben das HTML5-Video aktualisiert und einige Codecs veraltet. Es hat bei mir nach dem Entfernen der Codecs funktioniert.

Im folgenden Beispiel:

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

Wenn Sie einen Fehler mit sehen Uncaught (in promise)Dies bedeutet nur, dass Sie das Versprechen mit einem behandeln müssen. .catch()In diesem Fall wird .play()ein Versprechen zurückgegeben. Sie können entscheiden, ob Sie eine Nachricht protokollieren, Code ausführen oder nichts tun möchten. Solange Sie .catch()den Fehler haben, wird er behoben.

var n = new Audio();
n.pause();
n.currentTime = 0;
n.play().catch(function(e) {
  // console.log('There was an error', e);
});
seantomburke
quelle
es gibt kein Versprechen zurück
Martin Dawson
@MartinMazzaDawson Es gibt ein Versprechen zurück. Wenn Sie sich den klarstellenden Kommentar von xxx in der Frage ansehen, sagt er: "Es ist ein Fehler, hier ist der vollständige Fehler: Nicht erfasst (im Versprechen) DOMException: Die play () -Anforderung wurde durch einen Aufruf von pause () unterbrochen."
Seantomburke
-5

Ich habe einen Trick benutzt, um diesem Problem entgegenzuwirken. Definieren Sie eine globale Variable var audio.

und in der Funktionsprüfung

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

und in der Stoppfunktion

audio.pause();
audio = undefined;

also der nächste anruf von audio.play ist Audio ab '0' currentTime bereit

ich benutzte

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

aber es hat nicht funktioniert. Vielen Dank.

Gippy Aulakh
quelle