Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript HTML5 video event canplay not firing on Safari

I have a HTML page including Javascript which is intended to allow a video (actually just audio content in this case) to play using HTTP Live Streaming on any browser. In most cases it uses hls.js but, in the case of Apple products, I need to do things differently as Safari has native HLS support.

The full page is reproduced below but the important lines are these:

else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = 'music.m3u8';
    video.addEventListener('canplay', startPlaying);
    //document.addEventListener('DOMContentLoaded', startPlaying);
}

What should happen is that when the canplay event fires the startPlaying() function is called and this makes visible a button that the user can press to begin playing the video. However, on my friend's iPhone 8plus (iOS 11.3.1), this doesn't work: no button is ever visible. If, instead, I comment out the video.addEventListener() line and replace it with the document.addEventListener() line then it all works fine: the button is made visible and he can play the stream.

Can anyone spot what I'm doing wrong? Could be a rookey mistake as I'm not very experienced with this web/script stuff, gives me nose bleeds... I could, of course, leave it with the DOM load approach but it's not right and I'd rather be right.

<!DOCTYPE html PUBLIC "-//Netscape Comm. Corp.//DTD HTML//EN">
<html>
<script src="hls.js/dist/hls.js"></script>

<head><meta http-equiv="content-type" content="text/html; charset=UTF-8"></head>
<body>
<video id="video"></video>
<button id="play" hidden>Loading</button>
<script>
'use strict';
var video = document.getElementById('video');
var playButton = document.getElementById('play');

function startPlaying() {
    // For mobile browsers the start of playing has to
    // be performed by a user action otherwise it will
    // be ignored
    playButton.addEventListener('click', function() {
        video.play();
        video.muted = false;
        video.volume = 1;
        playButton.innerHTML = "Playing";
    });
    playButton.hidden = false;
    playButton.innerHTML = "Ready to play";
}

if (Hls.isSupported()) {
    var hls = new Hls();
    hls.loadSource('music.m3u8');
    hls.attachMedia(video);
    hls.on(Hls.Events.MANIFEST_PARSED, startPlaying);
}
// hls.js is not supported on platforms that do not have Media Source Extensions (MSE) enabled.
// When the browser has built-in HLS support (check using `canPlayType`), we can provide an HLS manifest (i.e. .m3u8 URL) directly to the video element through the `src` property.
// This is using the built-in support of the plain video element, without using hls.js.
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
    video.src = 'music.m3u8';
    video.addEventListener('canplay', startPlaying);
    //document.addEventListener('DOMContentLoaded', startPlaying);
}
</script>
</body>
</html>
like image 502
Rob Avatar asked Apr 26 '18 20:04

Rob


1 Answers

From the investigations in the other question, the workaround is to wait on the event loadedmetadata, so in my case video.addEventListener('loadedmetadata', startPlaying), as this is the last event you're going to get from the HTML5 video element on Safari unless you're in the user-controlled white list. Confirmed that this works on iOS 11.3.1.

like image 158
Rob Avatar answered Sep 23 '22 21:09

Rob