Làm cách nào để ngăn lỗi "Yêu cầu phát () bị gián đoạn bởi lệnh gọi tạm dừng ()"?


107

Tôi đã tạo một trang web mà nếu người dùng nhấp vào, nó sẽ phát ra âm thanh. Để ngăn âm thanh bị chồng chéo, tôi phải thêm mã:

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

Nhưng điều đó gây ra lỗi: The play() request was interrupted by a call to pause()
Xuất hiện mỗi khi sự kiện âm thanh được kích hoạt ngay sau một lần kích hoạt khác. Âm thanh vẫn phát tốt, nhưng tôi muốn ngăn thông báo lỗi này liên tục xuất hiện. Bất kỳ ý tưởng?


nó là một lỗi, hay nhiều thông báo hơn?
dandavis

Đó là một lỗi, đây là lỗi đầy đủ: Uncaught (trong lời hứa) DOMException: Yêu cầu play () bị gián đoạn bởi lệnh gọi tạm dừng ().
Owen M

7
đó là một lỗi mới hơn, đừng lo lắng về điều đó: bugs.chromium.org/p/chromium/issues/detail?id=593273
dandavis

3
Cách khắc phục đơn giản cho điều này là không gọi phát hoặc tạm dừng ngay sau nhau. Thay vào đó, hãy sử dụng các sự kiện phương tiện để xác định thời điểm tạm dừng hoặc phát. Ví dụ: onCanPlay(). Tất cả những câu trả lời này là hack bẩn.
Martin Dawson

1
Tôi đã gặp vấn đề ngược lại. Tôi đã cố gắng n.play() sau đó n.pause() . Đối với điều đó, bài viết Cơ bản về Web này mô tả giải pháp. tl; dr:n.play().then(() => { n.pause()})
totymedli

Câu trả lời:


84

Tôi cũng gặp phải vấn đề này gần đây - đây có thể là một điều kiện chạy đua giữa play()pause(). Có vẻ như có một tham chiếu đến vấn đề này hoặc một cái gì đó liên quan ở đây .

Như @Patrick đã chỉ ra, pausekhông trả lại lời hứa (hoặc bất cứ điều gì), vì vậy giải pháp trên sẽ không hoạt động. Mặc dù MDN không bật tài liệu pause(), nhưng trong bản nháp WC3 cho Media Elements , nó cho biết:

media.pause ()

Đặt thuộc tính bị tạm dừng thành true, tải tài nguyên phương tiện nếu cần.

Vì vậy, người ta cũng có thể kiểm tra pausedthuộc tính trong lệnh gọi lại thời gian chờ của họ.

Dựa trên câu trả lời SO tuyệt vời này , đây là một cách bạn có thể kiểm tra xem video có thực sự đang phát (hay không), vì vậy bạn có thể kích hoạt một lần phát () một cách an toàn mà không gặp lỗi.

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

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

Nếu không, câu trả lời của @Patrick sẽ hoạt động.


1
Như @ regency-software đã nói, phương thức pause không trả về Promise (không có tài liệu nào về .pause ()) mà chỉ là "undefined". Vì vậy, giải pháp này chỉ có thể được áp dụng cho các trường hợp play () sau đó pause ().
Splact

Cảm ơn bạn đã cung cấp thông tin - Tôi đã cập nhật câu trả lời của mình để phản ánh những gì phần mềm @regency đã đăng, điều này là chính xác và anh ấy cũng có một giải pháp hiệu quả :-).
JohnnyCoder

Làm thế nào bạn đến được 150ms là thời gian chờ đợi? có vẻ là vấn đề với chrome: bug.chromium.org/p/chromium/issues/detail?id=593273
connect2krish

Xem câu trả lời của @Regency Software để biết lý do hết thời gian chờ. Tôi mở rộng câu trả lời của họ, đó là một giải pháp tốt. Ngoài ra, câu trả lời của tôi tham chiếu đến liên kết bạn đã cung cấp ở đầu câu trả lời.
JohnnyCoder

Điều này sẽ không hoạt động để phát trực tuyến video. Nếu tôi khởi chạy video WebRTC, điều này vẫn đưa ra ngoại lệ cho bảng điều khiển.
Stepan Yakovenko

70

Sau nhiều giờ miệt mài và làm việc, tôi đã tìm ra giải pháp hoàn hảo .

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

Sau đó, bạn có thể chuyển đổi phát / tạm dừng nhanh nhất có thể, nó sẽ hoạt động bình thường .


1
Đây là cách tôi đạt được vấn đề. Tôi cảm thấy đây là một giải pháp tốt hơn nhiều so với dựa vào một thời gian chờ
Malcor

@Malcor Cảm ơn bạn, điều này sẽ khắc phục vấn đề cho tất cả mọi người
Nebojsa Sapic

Một số người có thể vui lòng đặt tiền thưởng cho câu trả lời này để giúp nó được ủng hộ nhanh hơn không?
màu

1
Tại sao nó không được đánh dấu là câu trả lời đúng? Chắc chắn đây là một giải pháp, không phải là một hack với thời gian chờ.
jeron-diovis 17/02/17

15
Tại sao hai biến lại cần thiết? Tôi không nói đây là một giải pháp tồi. Chỉ đang cố gắng mò mẫm nó.
benevolentprof

20

Tôi đã gặp sự cố này và gặp trường hợp tôi cần nhấn tạm dừng () rồi phát () nhưng khi sử dụng tạm dừng (). Then () tôi không xác định được.

Tôi thấy rằng nếu tôi bắt đầu phát 150ms sau khi tạm dừng, nó đã giải quyết được sự cố. (Hy vọng rằng Google sẽ sớm sửa chữa)

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

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

Nếu bạn có nghĩa là 150ms? Tôi đã thử một vài giá trị khác nhau và giải quyết vấn đề này cho mục đích của tôi. Tôi đã nhắm mục tiêu Chrome và Android và nó phù hợp với nhu cầu của ứng dụng của tôi. Nó có thể thấp hơn.
Patrick

3
vì vậy nó gần như là giá trị ngẫu nhiên không liên quan đến bất kỳ thứ gì khác ngoài cấy ghép của bạn. Cảm ơn bạn đã làm rõ !
y_nk

Tôi tò mò rằng bạn có đang sử dụng cùng một phần tử để phát nhiều âm thanh không? Điều đó sẽ giải thích vấn đề tải; một âm thanh vẫn được tải trong khi cố gắng phát âm thanh khác thông qua cùng một phần tử. Độ trễ "có thể" ngăn chặn nó mặc dù một bản sửa lỗi vụng về và độ trễ dài hơn / ngắn hơn có thể được sử dụng để có trải nghiệm tốt hơn / tốt nhất. Xóa và tạo lại các phần tử một cách nhanh chóng đã là SOP của tôi bỏ qua một số rò rỉ âm thanh / video và bộ nhớ.
tree

1
trông giống như một lỗi chrome: bug.chromium.org/p/chromium/issues/detail?id=593273
connect2krish

8
Không nên sử dụng thời lượng setTimeout tùy ý để giải quyết các điều kiện của cuộc đua.
Gadget Blaster


5

thử nó

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


2

Tùy thuộc vào mức độ phức tạp mà bạn muốn giải pháp của mình, điều này có thể hữu ích:

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

Điều này hơi quá mức cần thiết, nhưng hữu ích khi xử lý Lời hứa trong các tình huống duy nhất.


2

Các giải pháp được đề xuất ở đây không phù hợp với tôi hoặc ở đâu lớn, vì vậy tôi đang tìm kiếm thứ khác và tìm thấy giải pháp được đề xuất bởi @dighan trên bountysource.com/issues/

Vì vậy, đây là mã đã giải quyết vấn đề của tôi:

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

Nó vẫn báo lỗi vào bảng điều khiển, nhưng ít nhất video đang phát :)


1

Có lẽ một giải pháp tốt hơn cho điều này như tôi đã tìm ra. Spec nói như được trích dẫn từ @JohnnyCoder:

media.pause ()

Đặt thuộc tính bị tạm dừng thành true, tải tài nguyên phương tiện nếu cần.

-> tải nó

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

cho biết trạng thái sẵn sàng của phương tiện CÓ_ENOUGH_DATA = 4

Về cơ bản, chỉ tải video nếu nó chưa được tải. Đã xảy ra lỗi được đề cập đối với tôi, vì video không được tải. Có lẽ tốt hơn là sử dụng thời gian chờ.


1

đã loại bỏ tất cả các lỗi: (typecript)

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

1

Với tính năng phát trực tiếp, tôi cũng gặp phải vấn đề tương tự. và cách khắc phục của tôi là cái này. Từ TAG video html, hãy đảm bảo xóa "tự động phát" và sử dụng mã bên dưới này để phát.

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
Giải pháp tuyệt vời !!
Junaid Mukhtar

1

Chrome trả lại Lời hứa trong các phiên bản mới nhất. Nếu không, chỉ cần:

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

1

Tôi có cùng một vấn đề, cuối cùng tôi giải quyết bằng cách:

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

1

Đoạn mã này đã sửa cho tôi!

Mã sửa đổi của @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

Tôi đã sửa nó bằng một số mã dưới đây:

Khi bạn muốn chơi, hãy sử dụng như sau:

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

Tương tự, khi bạn muốn tạm dừng:

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

video_play.on('canplay', function() {
  video_play.trigger('pause');
});

0

Đây là một giải pháp khác nếu lý do là tải xuống video của bạn quá chậm và video không được lưu vào bộ đệm:

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


0

Có vẻ như rất nhiều lập trình viên gặp phải vấn đề này. một giải pháp nên khá đơn giản. phần tử media trả về Promisetừ các hành động

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

nên làm thủ thuật


0

đây là một giải pháp từ blog của 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

Tất cả video hỗ trợ trình duyệt mới chỉ được phát tự động với chế độ tắt tiếng, vì vậy vui lòng đặt Một cái gì đó như thế này

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

URL của video phải khớp với trạng thái SSL nếu trang web của bạn đang chạy với https thì URL video cũng phải ở https và tương tự đối với HTTP


0

Giải pháp sạch nhấtđơn giản nhất :

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

0

Lý do thứ nhất - tạm dừng cuộc gọi mà không cần đợi lời hứa chơi giải quyết

quá nhiều câu trả lời cho tình huống này, vì vậy tôi sẽ chỉ tham khảo tài liệu tốt nhất cho vấn đề đó:

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

Lý do thứ hai - gọi phát khi tab không được tập trung

Trong trường hợp này, trình duyệt có thể làm gián đoạn playbằng cách gọipause khi tab không nằm trong tiêu điểm. để tiết kiệm tài nguyên cho tab đang hoạt động.

Vì vậy, bạn có thể chỉ cần đợi tab được tập trung trước khi gọi phát:


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

Tôi đã gặp phải vấn đề tương tự và đã giải quyết nó bằng cách thêm động autoplaythuộc tính thay vì sử dụng play(). Bằng cách đó, trình duyệt đã tìm ra cách chơi mà không gặp phải tình trạng cuộc đua.


-1

Cố gắng làm cho video tự động phát lặp lại bằng cách gọi play()khi video kết thúc, giải pháp hết thời gian chờ đã không hiệu quả với tôi (tuy nhiên thời gian chờ quá lâu).

Nhưng tôi phát hiện ra rằng bằng cách sao chép / thay thế video bằng jQuery khi video kết thúc, nó sẽ lặp lại đúng cách.

Ví dụ:

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

Tôi đang sử dụng Chrome 54.0.2840.59 (64-bit) / OS X 10.11.6


-1

Tôi nghĩ rằng họ đã cập nhật video html5 và không dùng một số codec nữa. Nó hoạt động với tôi sau khi loại bỏ codec.

Trong ví dụ dưới đây:

<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

Khi bạn thấy lỗi với Uncaught (in promise)Điều này chỉ có nghĩa là bạn cần xử lý lời hứa với .catch()trong trường hợp này, .play()trả về một lời hứa. Bạn có thể quyết định xem bạn muốn ghi lại một tin nhắn, chạy một số mã hay không làm gì cả, nhưng miễn là bạn có .catch(), lỗi sẽ biến mất.

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

nó không trả lại một lời hứa
Martin Dawson

@MartinMazzaDawson Nó trả lại một lời hứa. Nếu bạn nhìn vào bình luận làm rõ của xxx trong câu hỏi, anh ấy nói "Đó là một lỗi, đây là lỗi đầy đủ: Uncaught (trong lời hứa) DOMException: Yêu cầu play () đã bị gián đoạn bởi lệnh tạm dừng ()."
seantomburke

-5

Tôi đã sử dụng một thủ thuật để chống lại vấn đề này. Xác định một biến âm thanh toàn cục var;

và trong kiểm tra chức năng

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

và trong chức năng dừng

audio.pause();
audio = undefined;

vì vậy cuộc gọi tiếp theo của audio.play , âm thanh sẽ sẵn sàng từ '0' currentTime

Tôi đã sử dụng

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

nhưng nó không hoạt động. Cảm ơn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.