「play()リクエストがpause()の呼び出しによって中断された」というエラーを防ぐ方法は?


107

ユーザーがクリックすると音が鳴るサイトを作りました。音が重ならないようにするには、コードを追加する必要がありました。

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

ただし、これによりエラーが発生します。 The play() request was interrupted by a call to pause()
サウンドイベントがトリガーされるたびに、別のトリガーの直後に起動します。サウンドは引き続き正常に再生されますが、このエラーメッセージが常にポップアップするのを防ぎたいと思います。何か案は?


エラーですか、それとも通知ですか?
dandavis

これはエラーです。完全なエラーは次のとおりです:キャッチされていません(約束どおり)DOMException:pause()の呼び出しによってplay()要求が中断されました。
Owen M

7
新しいバグですので、心配しないでください:bugs.chromium.org/p/chromium/issues/detail
id=

3
このための簡単な修正は、playを呼び出したり、お互いの直後に一時停止したりしないことです。代わりにメディアイベントを使用して、一時停止または再生するタイミングを決定します。例:onCanPlay()。これらすべての答えは汚いハックです。
Martin Dawson、

1
私は反対の問題を抱えていました。n.play() その後 しようとしn.pause()。そのため、このWeb Fundamentalsの記事でソリューションについて説明します。tl; dr:n.play().then(() => { n.pause()})
totymedli 2018

回答:


84

私も最近この問題に遭遇しました-これはとの間の競合状態である可能性がplay()ありpause()ます。この問題への参照、またはここに関連する何かがあるようです

以下のよう@Patrickは指摘し、pause約束(または何か)を返していないので、上記の解決策は機能しませんありません。MDNは上のドキュメントを持っていませんがpause()で、メディア要素のためのWC3ドラフト、それは言います:

media.pause()

paused属性をtrueに設定し、必要に応じてメディアリソースをロードします。

したがってpaused、タイムアウトコールバックで属性を確認することもできます。

このすばらしいSO回答に基づいて、ビデオが本当に再生されている(または再生されていない)かどうかを確認できる方法を示します。これにより、エラーなしで安全にplay()をトリガーできます。

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

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

それ以外の場合は、@ Patrick答えが機能するはずです。


1
@ regency-softwareが言うように、pauseメソッドはPromiseを返しません(.pause()にはドキュメントはありません)が、単に「未定義」です。したがって、このソリューションは、play()、次にpause()の場合にのみ適用できます。
Splact 2016年

情報をありがとう-私は@regencyソフトウェアが投稿した内容を反映するように私の回答を更新しましたが、これは正解でした。
JohnnyCoder 2016年

どのようにして待ち時間として150msに到達しましたか?Chromeの
id=

タイムアウトの理由については、@ Regency Software回答を参照してください。私は彼らの答えを拡張しましたが、それは良い解決策でした。また、私の回答は、回答の最初に提供したリンクを参照しています。
JohnnyCoder 2016

これはストリーミングビデオでは機能しません。WebRTCビデオを初期化している場合でも、コンソールには例外があります。
ステパンヤコヴェンコ2017年

70

何時間にもわたって作業した後、私は完璧な解決策を見つけました。

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

その後、できるだけ早く再生/一時停止を切り替えることができ、正しく動作します


1
これは私が問題を達成した方法です。これはタイムアウトに依存するよりもはるかに優れた解決策だと思います
Malcor

@Malcorありがとうございます、これですべての人の問題が解決します
Nebojsa Sapic

誰かがこの回答に賞金をかけて、より速く賛成することはできますか?
カラーの追加2017年

1
なぜそれが正解としてマークされていないのですか?間違いなくこれは解決策であり、タイムアウトによるハックではありません。
jeron-diovis 2017

15
なぜ2つの変数が必要なのですか?これが悪い解決策だと言っているのではありません。ただそれを理解しようとしています。
benevolentprof

20

私はこの問題に遭遇し、pause()を押してからplay()を押す必要がある場合がありますが、pause()。then()を使用すると、未定義になります。

一時停止してから150ミリ秒後に再生を開始すると、問題が解決することがわかりました。(できればGoogleですぐに修正します)

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

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

150msという意味ですか?私はいくつかの異なる値を試してみて、私の目的のためにこれに落ち着きました。私はChromeとAndroidをターゲットにしていましたが、それは私のアプリのニーズに適合しました。低くできるかもしれません。
Patrick

3
したがって、それはあなたの実装以外には何も関係がないので、ほとんどランダムな値です。説明をありがとう!
y_nk 2016年

同じ要素を使用して複数のサウンドを再生していますか?これはロードの問題を説明します。同じ要素を介して別のサウンドを再生しようとしたときに、1つのサウンドがまだロードされています。遅延は「止める」ことができますが、その不器用な修正とより長い/より短い遅延は、より良い/最高の体験のために使用できます。その場で要素をクリアして再作成することが私のSOPであり、多くのオーディオ/ビデオおよびメモリリークをスキップします。
ツリー


8
競合状態を解決するために、任意のsetTimeout期間を使用しないでください。
ガジェットブラスター


5

それを試してみてください

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


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を処理するときに役立ちます。


2

ここで提案された解決策は私にとっても効果的でもなかったため、他のものを探していたところ、@ dighanがbountysource.com/issues/で提案した解決策を見つけました

だからここに私の問題を解決したコードがあります:

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

それでもコンソールにエラーがスローされますが、少なくともビデオは再生されています:)


1

私が理解したように、これのより良い解決策かもしれません。Specは@JohnnyCoderから引用したように言っています:

media.pause()

paused属性をtrueに設定し、必要に応じてメディアリソースをロードします。

->ロードする

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

メディアの準備状態を示しますHAVE_ENOUGH_DATA = 4

基本的に、ビデオがまだロードされていない場合のみロードします。ビデオがロードされなかったため、言及されたエラーが発生しました。タイムアウトを使用するよりも良いかもしれません。


1

すべてのエラーを削除しました:(typescript)

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

1

ライブストリーミングでも同じ問題に直面していました。そして私の修正はこれです。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;
                    }
                }
            });
        }

1
素晴らしいソリューション!!
Junaid Mukhtar 2017年

1

ChromeはPromiseを最新バージョンで返します。そうでなければ、単に:

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

1

私は同じ問題を抱えていますが、最後に私は次の方法で解決します:

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

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

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

0

動画のダウンロードが非常に遅く、動画がバッファされていないことが理由である場合の別の解決策は次のとおりです。

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


0

多くのプログラマーがこの問題に遭遇したようです。ソリューションは非常にシンプルでなければなりません。メディア要素Promiseはアクションから戻るので

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

トリックを行う必要があります


0

これはグーグルブログからの解決策です:

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

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でも同じである必要があります


0

きれいな最も簡単な解決策:

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

0

理由1-プレイの約束が解決するのを待たずにポーズを呼び出す

このシナリオでは回答が多すぎるため、その問題に最適なドキュメントを参照します。

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

理由2-タブがフォーカスされていないときにplayを呼び出す

この場合、ブラウザは中断可能性がありplay呼び出すことにより、pauseタブがフォーカスされていないときにがあります。アクティブなタブのリソースを節約するため。

したがって、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();

-1

私は同じ問題に遭遇し、autoplayを使用するのではなく属性を動的に追加することで解決しましたplay()。このようにして、ブラウザーは競合状態に陥ることなく再生することがわかりました。


-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を使用しています


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


-1

Uncaught (in promise)Thisのエラーが表示された場合、これは単に、Promiseを処理する必要があることを意味します。.catch()この場合、.play()Promiseを返します。メッセージをログに記録するか、コードを実行するか、何もしないかを決定できますが.catch()、エラーが発生している限り、エラーは発生しません。

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

それは約束を返しません
マーティン・ドーソン

@MartinMazzaDawson約束を返します。「それはエラーです。ここに完全なエラーがあります:キャッチされていません(約束されています)DOMException:play()リクエストがpause()の呼び出しによって中断されました。
seantomburke 2017年

-5

私はこの問題に対処するためにトリックを使いました。グローバル変数var audioを定義します。

そして機能チェックで

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

そして停止機能で

audio.pause();
audio = undefined;

の次の呼び出しではaudio.play、オーディオは '0' currentTimeから準備されます

使った

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

しかし、それはうまくいきませんでした。ありがとう。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.