จะป้องกันข้อผิดพลาด“ การร้องขอ play () ถูกขัดจังหวะด้วยข้อผิดพลาด call to pause () ได้อย่างไร?


107

ฉันสร้างเว็บไซต์ที่หากผู้ใช้คลิกมันจะส่งเสียง เพื่อป้องกันไม่ให้เสียงทับซ้อนกันฉันต้องเพิ่มรหัส:

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

แต่นั่นทำให้เกิดข้อผิดพลาด: The play() request was interrupted by a call to pause()
จะเกิดขึ้นทุกครั้งที่เหตุการณ์เสียงถูกเรียกทันทีหลังจากทริกเกอร์อื่น เสียงยังคงเล่นได้ดี แต่ฉันต้องการป้องกันไม่ให้ข้อความแสดงข้อผิดพลาดนี้โผล่ขึ้นมาอย่างต่อเนื่อง ความคิดใด ๆ ?


มันเป็นข้อผิดพลาดหรือมากกว่าการแจ้งให้ทราบ?
dandavis

นี่คือข้อผิดพลาดนี่คือข้อผิดพลาดทั้งหมด: Uncaught (ตามสัญญา) DOMException: คำขอ play () ถูกขัดจังหวะด้วยการเรียกหยุดชั่วคราว ()
Owen M

7
เป็นบั๊กที่ใหม่กว่าไม่ต้องกังวล: bugs.chromium.org/p/chromium/issues/detail?id=593273
dandavis

3
วิธีแก้ไขง่ายๆสำหรับเรื่องนี้คืออย่าโทรเล่นหรือหยุดชั่วคราวหลังจากกัน ใช้เหตุการณ์ของสื่อแทนเพื่อกำหนดเวลาที่จะหยุดชั่วคราวหรือเล่น ตัวอย่าง: onCanPlay(). คำตอบทั้งหมดนี้เป็นการแฮ็กที่สกปรก
Martin Dawson

1
ฉันมีปัญหาตรงกันข้าม ผมพยายามที่จะแล้วn.play() n.pause()ด้วยเหตุนี้บทความพื้นฐานเกี่ยวกับเว็บนี้จะอธิบายวิธีแก้ปัญหา tl; dr:n.play().then(() => { n.pause()})
totymedli

คำตอบ:


84

ฉันได้พบปัญหานี้เมื่อเร็ว ๆ นี้เช่นกัน - นี้อาจจะมีการแย่งชิงระหว่างและplay() pause()ดูเหมือนว่ามีการอ้างอิงถึงปัญหานี้หรือสิ่งที่เกี่ยวข้องกับที่นี่

ดังที่@Patrickชี้ให้เห็นว่าpauseไม่คืนสัญญา (หรืออะไรเลย) ดังนั้นวิธีแก้ปัญหาข้างต้นจะไม่ได้ผล แม้ว่า MDN จะไม่ได้เปิดใช้เอกสารpause()แต่ในแบบร่าง WC3 สำหรับ Media Elementsจะระบุว่า:

media.pause ()

ตั้งค่าแอตทริบิวต์ paused เป็น true โหลดทรัพยากรสื่อหากจำเป็น

ดังนั้นเราอาจตรวจสอบpausedแอตทริบิวต์ในการโทรกลับแบบหมดเวลา

จากคำตอบ SO ที่ยอดเยี่ยมนี้คุณสามารถตรวจสอบได้ว่าวิดีโอนั้น (หรือไม่) กำลังเล่นจริงหรือไม่เพื่อให้คุณสามารถเริ่มการเล่น () ได้อย่างปลอดภัยโดยไม่มีข้อผิดพลาด

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

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

ไม่เช่นนั้นคำตอบของ@Patrickควรใช้งานได้


1
ดังที่ @ regency-software กล่าวไว้ว่าวิธีการหยุดชั่วคราวจะไม่ส่งคืน Promise (ไม่มีเอกสารใน. pause ()) แต่เป็นเพียง "ไม่ได้กำหนด" ดังนั้นวิธีนี้สามารถใช้ได้เฉพาะกับกรณี play () จากนั้นหยุดชั่วคราว ()
Splact

ขอบคุณสำหรับข้อมูล - ฉันอัปเดตคำตอบเพื่อให้สอดคล้องกับซอฟต์แวร์ @regency ที่โพสต์ซึ่งถูกต้องและเขายังมีวิธีแก้ปัญหาที่ใช้งานได้ :-)
JohnnyCoder

คุณมาถึง 150ms เป็นเวลารอได้อย่างไร? น่าจะเป็นปัญหาเกี่ยวกับ Chrome: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish

ดูคำตอบของ@Regency Softwareสำหรับเหตุผลการหมดเวลา ฉันขยายคำตอบของพวกเขาซึ่งเป็นทางออกที่ดี นอกจากนี้คำตอบของฉันยังอ้างอิงลิงก์ที่คุณให้ไว้ในตอนต้นของคำตอบ
JohnnyCoder

วิธีนี้ใช้ไม่ได้กับการสตรีมวิดีโอ หากฉันเริ่มต้นวิดีโอ WebRTC สิ่งนี้ยังคงให้ข้อยกเว้นสำหรับคอนโซล
Stepan Yakovenko

70

หลังจากชั่วโมงของการทำงาน seaching และฉันพบที่สมบูรณ์แบบวิธีการแก้ปัญหา

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

โปรดให้ความสำคัญกับคำตอบนี้เพื่อเพิ่มคะแนนให้เร็วขึ้นได้ไหม
AddingColor

1
ทำไมจึงไม่ทำเครื่องหมายว่าเป็นคำตอบที่ถูกต้อง? แน่นอนว่านี่เป็นวิธีแก้ปัญหาไม่ใช่แฮ็คที่หมดเวลา
jeron-diovis

15
เหตุใดสองตัวแปรจึงจำเป็น ฉันไม่ได้บอกว่านี่เป็นวิธีแก้ปัญหาที่ไม่ดี แค่พยายามที่จะคร่ำครวญ
เมตตา

20

ฉันประสบปัญหานี้และมีกรณีที่ฉันต้องกด pause () แล้วเล่น () แต่เมื่อใช้ pause () จากนั้น () ฉันไม่ได้กำหนด

ฉันพบว่าถ้าฉันเริ่มเล่น 150 มิลลิวินาทีหลังจากหยุดชั่วคราวมันจะสามารถแก้ไขปัญหาได้ (หวังว่า Google จะแก้ไขเร็ว ๆ นี้)

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

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

ถ้าคุณหมายถึง 150ms? ฉันลองใช้ค่าที่แตกต่างกันเล็กน้อยและตัดสินตามจุดประสงค์ของฉัน ฉันกำหนดเป้าหมาย Chrome และ Android และเหมาะกับความต้องการของแอปของฉัน มันอาจจะต่ำลงได้
Patrick

3
ดังนั้นจึงเป็นค่าสุ่มเกือบจะไม่เกี่ยวข้องกับสิ่งอื่นใดนอกจากนัยของคุณ ขอขอบคุณสำหรับการชี้แจง !
y_nk

ฉันอยากรู้ว่าคุณใช้องค์ประกอบเดียวกันเพื่อเล่นหลายเสียงหรือไม่? นั่นจะอธิบายปัญหาการโหลด เสียงหนึ่งยังคงโหลดอยู่ในขณะที่พยายามเล่นเสียงอื่นผ่านองค์ประกอบเดียวกัน ความล่าช้า "สามารถ" หยุดได้แม้ว่าจะเป็นการแก้ไขที่ยุ่งยากและอาจใช้ความล่าช้าที่ยาวขึ้น / สั้นลงเพื่อประสบการณ์ที่ดีขึ้น / ดีที่สุด การล้างและสร้างองค์ประกอบใหม่ในทันทีเป็น SOP ของฉันซึ่งข้ามการรั่วไหลของเสียง / วิดีโอและหน่วยความจำจำนวนมาก
ต้นไม้

1
ดูเหมือนบั๊กของ Chrome: bugs.chromium.org/p/chromium/issues/detail?id=593273
connect2krish

8
ไม่ควรใช้ระยะเวลา setTimeout โดยพลการเพื่อแก้ปัญหาสภาพการแข่งขัน
Gadget Blaster




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

นี่เป็นเรื่องที่มากเกินไป แต่ช่วยเมื่อจัดการกับคำสัญญาในสถานการณ์ที่ไม่เหมือนใคร


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

ด้วยการสตรีมสดฉันประสบปัญหาเดียวกัน และการแก้ไขของฉันคือสิ่งนี้ จากแท็กวิดีโอ html อย่าลืมลบ "เล่นอัตโนมัติ" และใช้โค้ดด้านล่างนี้เพื่อเล่น

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

1

Chrome ส่งคืนสัญญาในเวอร์ชันใหม่ล่าสุด มิฉะนั้นเพียง:

        n.pause();
        n.currentTime = 0;
        setTimeout(function() {n.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

นี่คือวิธีแก้ปัญหาจากบล็อกของ 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)
}

0

เบราว์เซอร์ใหม่ทั้งหมดรองรับวิดีโอที่จะเล่นอัตโนมัติโดยปิดเสียงเท่านั้นดังนั้นโปรดใส่สิ่งนี้

<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


0

สะอาดและง่ายที่สุดวิธีการแก้ปัญหา:

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

0

เหตุผลที่หนึ่ง - การโทรหยุดชั่วคราวโดยไม่ต้องรอสัญญาว่าจะเล่นเพื่อแก้ไข

คำตอบสำหรับสถานการณ์นี้มากเกินไปดังนั้นฉันจะอ้างถึงเอกสารที่ดีที่สุดสำหรับปัญหานั้น:

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

เหตุผลที่สอง - การโทรเล่นเมื่อแท็บไม่ได้โฟกัส

ในกรณีนี้เบราว์เซอร์อาจขัดขวางการplayโทรpauseเมื่อแท็บไม่ได้โฟกัส เพื่อประหยัดทรัพยากรสำหรับแท็บที่ใช้งานอยู่

ดังนั้นคุณสามารถรอให้แท็บถูกโฟกัสก่อนที่จะเรียกเล่น:


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)สิ่งนี้หมายความว่าคุณต้องจัดการกับคำสัญญาด้วย.catch()ในกรณีนี้ให้.play()ส่งคืนคำสัญญา คุณสามารถตัดสินใจได้ว่าต้องการบันทึกข้อความเรียกใช้รหัสหรือไม่ทำอะไรเลย แต่ตราบใดที่คุณมี.catch()ข้อผิดพลาดจะหายไป

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

มันไม่คืนคำสัญญา
Martin Dawson

@MartinMazzaDawson มันคืนคำสัญญา หากคุณดูความคิดเห็นที่ชัดเจนของ xxx ในคำถามที่เขาระบุว่า "มันเป็นข้อผิดพลาดนี่คือข้อผิดพลาดทั้งหมด: Uncaught (ตามสัญญา) DOMException: คำขอ play () ถูกขัดจังหวะด้วยการเรียกให้หยุดชั่วคราว ()"
seantomburke

-5

ฉันได้ใช้กลอุบายเพื่อตอบโต้ปัญหานี้ กำหนดเสียงตัวแปรสากล

และในการตรวจสอบฟังก์ชัน

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.