wnrph
wnrph

Reputation: 3393

readyState issue with HTML5 video elements on ios safari

It seems on the iPad (iOS v. 5.1.1), Safari does not keep a video element's readyState value according to specification. Even while loading from the video source readyState equals zero.

I've made a demonstration jsfiddle which continuously checks the video's readyState. A funny observation: the readyState changes only after clicking the play button.

Actually, I've expected the readyState to switch to a higher number during loading (as it is the case with all browsers on the desktop I've tested--including Safari.) Is there a workaround? Am I getting something wrong here?

Upvotes: 4

Views: 11434

Answers (3)

dcts
dcts

Reputation: 1639

In iOS mobile (no matter if safari or chrome), you need to tell the browser actively to load

// example with audio
const audio = new Audio("url...");
audio.load();  // this is needed on iOS mobile

// example with video
const video = new Video("url...");
video.load();  // this is needed on iOS mobile

Thanks for Harry Stevens to pointing that out.

Upvotes: 1

Harry Stevens
Harry Stevens

Reputation: 1423

I ran into this problem recently and found a solution, so I thought I'd come share it.

If you want to control your video with JavaScript, the basic pattern is to wait for the video to load, and then advance the frames with code. Something like this:

// Select the video element
const video = document.querySelector("video");

// Use an animation frame to wait for it to load
let req;
function wait(){
  req = window.requestAnimationFrame(wait);

  // readyState will never reach 4 on mobile Safari...
  if (video.readyState === 4) {
    window.cancelAnimationFrame(req);
    doSomethingWithYourVideo();
  }
}
req = wait();

I've also seen people do this window.setInterval instead of window.requestAnimationFrame, but the basic idea is the same.

On mobile Safari, however, the readyState will never reach 4, even if you set your video element to muted. Your video will never play.

But there is a simple fix: video.load(). So, this works:

// Select the video element
const video = document.querySelector("video");

// Tell the browser to load the video
video.load();

// Use an animation frame to wait for it to load
let req;
function wait(){
  req = window.requestAnimationFrame(wait);

  // Now, readyState will reach 4 on mobile Safari...
  if (video.readyState === 4) {
    window.cancelAnimationFrame(req);
    doSomethingWithYourVideo();
  }
}
req = wait();

Upvotes: 2

Torsten Walter
Torsten Walter

Reputation: 5792

From the Apple developer documentation:

Note: The preload attribute is supported in Safari 5.0 and later. Safari on iOS never preloads.

According to Apple the desired behavior on a mobile device is that loading only starts after you actively request the resource so as to not waste bandwidth or battery.

Regarding your question this means that Apple is adhering to the spec. Since no preload occurs and loading only starts after you click the play button the readyState is zero before that point in time.

However, the video tag has special events which are supposed to give more information than readyState.

  • onCanplay
  • onCanplaythrough
  • onProgress

Again, quoting the Apple developer library (Using DOM Events to monitor load progress)

Note: On the iPad, Safari does not begin downloading until the user clicks the poster or placeholder. Currently, downloads begun in this manner do not emit progress events.

Upvotes: 6

Related Questions