Detect when mobile Safari stops playing video because second video starts

Mobile Safari allows you to play one audio or video stream at a time .

Multiple simultaneous audio or video streams

Currently, all devices running iOS are limited to playing one audio or video at any time. Play multiple videos Side partially overlapping or fully overlapping - currently supported on iOS devices.

If you play the second video, it stops first. I need to determine when this happens so that I can disappear in the play button that appears next to the video, and I would also like to reset it to be in the first frame, because leaving its average animation looks awful.

Unfortunately, the <video> element does not seem to raise the event "finished" or "paused" when the video is forcibly stopped like that.

  $('video').off('ended pause').on('ended paused', function () { alert('ended'); // don't get here except when the video naturally ends } 

I cannot find any other events that correspond to a "forced stop". ( See Apple events for HTMLMediaElement )

Should I do it myself and add a .playing class to my video and check it when playing the second video? This works if I control every video on the page, but as soon as I attach a YouTube video to it, it becomes much more complicated. Any best solutions

+8
javascript html5-video mobile-safari
source share
2 answers

This solution seems a bit hacky, but if the Safari browser browser does not throw an event when the video is stopped, there are many options left -

To detect if a video has stopped, we can first make sure that the script knows when the video is playing, therefore:

 var isPlaying1 = false, isPlaying2 = false, // if more videos an array is better to use, or reuse lastTime1 = 0, lastTime2 = 0; // etc. $('video1').on('playing', function() { isPlaying1 = true; }); $('video1').on('ended', function() { isPlaying1 = false; }); 

This sets the play flag when starting the video. Use the ended event to set it to false if it was played back to the end or was stopped manually.

The next step is to poll the current video playback time to see if it changes. If no changes are specified, the video does not play (and does not get into the event to be completed):

 function check() { if (isPlaying1) { var video = $('video1')[0]; if (video.currentTime === lastTime1) { // video has stopped isPlaying1 = false; video.currentTime = lastTime1 = 0; //reset time } else { lastTime1 = video.currentTime; } } } var timerID = setInterval(check, 1000/15); // start check 

The scan rate should not exceed 30 frames per second. This is due to the fact that the time stamp will not be changed from what would correspond to the time from one frame to another. To be safe, use half the speed, as in the example for the most famous frame rate (videos rarely exceed 30 frames per second in the United States or 25 frames per second in Europe). If you know that videos will be played at a lower rate, the lowest rate should be here. It can also be reduced to reduce the overall load.

To stop checking, just call:

 clearInterval(timerID); // timerID is in global scope 

You may encounter a race condition between the completed event and the validation (as both create asynchronous behavior). If that matters, it depends on how you deal with two situations.

As said, it feels like a “hacker”, it hasn’t been tested on my part (only theorized, because I can’t configure the entire test environment for it), but I hope this helps you bypass this Safari limitation of the mobile browser.

+2
source share

If the event does not fire only when another video is playing, perhaps when we play the video, we can simply trigger the ended event for all other video being played. To track video playback, we could use the javascript property attached to the video object. Something like

 $("video").on("ended",function(){ this.playing=false this.currentTime=0 console.log(this.src+" has ended") }) $("video").on("play",function(){ var that=this this.playing=true //video that is playing is "playing" $("video").each(function(i,o){ if(o.playing && !$(o).is($(that)) ){ //for all the other "playing" video o.pause() $(o).trigger("ended") } }) }) 

Example (tested on iPad mini)

The downside of this is that it also applies to desktop browsers, which may be undesirable. As for YouTube videos embedded in the same page, we could use the Youtube API . The APIs use postMessage to communicate with each other, so I used the code below to stop the video tags when playing YouTube videos.

 window.addEventListener('message',function(event) { //probably should check origin var data=JSON.parse(event.data) if(data.info && ( data.info.playerState == 1 //buffering || data.info.playerState == 3 )){ //or playing $("video").each(function (i, o) { if(o.playing){ o.pause() $(o).trigger("ended") } }) } },false); 

Example

+2
source share

All Articles