7

If the user wants to stop the HTML5 media, for example by clicking “pause” native control button, we get "onpause" event. At the same time, if media element reaches the end of the specified fragment, it triggers the same "onpause" event automatically. Is it possible to separate one from another? In JQuery style,

<video id="video1" src="url/video.webm#t=10,20" controls></video>

<script type="text/javascript">
  $(window).load(function () { 
    $('#video1').on("manualpause", function () {
      alert("you paused this media manually!");
    });
    $('#video1').on("fragmentend", function () {
      alert("you've reached the end of the fragment! your media is now paused automatically!");
    });
  });
</script>

I tried to make use of "ontimeupdate" event, but refused: I want to react exactly when an automatic pause (caused by reaching the end of a fragment) takes place.

lyrically wicked
  • 1,185
  • 12
  • 26
  • 1
    https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events From the official MDN documentation, there apparently are both _ended_ and _pause_ events. is this what you are looking for? **ended** _Sent when playback completes._, while **pause** _Sent when playback is paused._ – briosheje May 18 '15 at 07:44
  • The problem is that reaching the end of a media fragment triggers the "onpause" event (not "ended"), and I can't understand how to catch such a specific, automatic pause. The event is the same in both cases, but its **nature** (from the user's point of view) is different! – lyrically wicked May 18 '15 at 07:48
  • according to the documentation, _ended_ throws when the playback completes, hence it should be thrown when the media ends, while the pause event shouldn't be called. Are you 100% sure that the pause event is being thrown? – briosheje May 18 '15 at 07:53
  • Can you try $("#video1").bind('ended', function(){ ... ? – Eugene J. Lee May 18 '15 at 07:54
  • Why are you referring to "ended"? The end of a fragment is not the end of a media! It **doesn't mean that the playback completes**, it means **pause**! – lyrically wicked May 18 '15 at 07:59

2 Answers2

3

An ended event will only be issued when the complete track has finished. When you play a fragment it will only pause the track at the end of the fragment as the track itself has not ended (unless the end time for the fragment happened to be the end as well).

A media element is said to have paused for user interaction when its paused attribute is false, the readyState attribute is either HAVE_FUTURE_DATA or HAVE_ENOUGH_DATA and the user agent has reached a point in the media resource where the user has to make a selection for the resource to continue.

The ended event will only occur if:

A media element is said to have ended playback when:

The element's readyState attribute is HAVE_METADATA or greater, and

Either:

  • The current playback position is the end of the media resource, and
  • The direction of playback is forwards, and
  • Either the media element does not have a loop attribute specified, or the media element has a current media controller.
Or:
  • The current playback position is the earliest possible position, and
  • The direction of playback is backwards.

Source

To detect if the pause event was triggered due to end of fragment you can compare the currentTime with the fragment end-time (and yes, there is a theoretical chance that you could hit the pause button at exactly this time as well, but this will be as close as you get with the audio element unless the event itself has a secret property revealing the source of pause, of which I am unaware of).

Since we're dealing with floating point values you need to compare the time using an epsilon. Assuming you parse or other wise have a way to get the end-time for the fragment, you can do:

function onPauseHandler(e) {
    var fragmentEndTime = ...;   // get/parse end-fragment into this var
    if (isEqual(this.currentTime, fragmentEndTime)) {
      // likely that fragment ended
    }
    else {
      // a manual pause
    }
}

function isEqual(n1, n2) {
   return Math.abs(n1 - n2) < 0.00001
}
  • Thank you. Well, that's exactly what I meant when wrote "I tried to make use of 'ontimeupdate' event", but I don't know... it seems like a very straightforward hack. Maybe we need to check if a media itself was clicked (does clicking a "pause" trigger "onclick"?). But I'll need to accept this if there's no better way... – lyrically wicked May 20 '15 at 03:49
  • @lyricallywicked you may be able to [detect f.ex. click events](http://jsfiddle.net/epistemex/rch748dk/) in some browsers (e.g. works in FF but not in Chrome) which makes it unreliable, or possibly better, provide custom buttons for controls. –  May 20 '15 at 10:12
  • Actually [4.7.10.8 Playing the media resource](http://www.w3.org/TR/html5/embedded-content-0.html#playing-the-media-resource) would be a better reference, because there it says `When the current playback position reaches the end [...], then the user agent must follow these steps:`, `4. [...] and the media element has still ended playback, [...], and paused is false, changes paused to true and fires a simple event named pause at the media element.`. I like your workaround, thus +1. – try-catch-finally Sep 11 '15 at 15:31
1

This came up for me today when searching for "why does onpause also fire when onended occurs". I wanted to separate the logic between an onpause event and on onended event.

This was my take on it:

videoRef.onpause = (e) => {
  if (e.target.currentTime != e.target.duration) {
    // handleOnPause();
  }
}

I have both onpause and onended handlers registered, with onpause running code when it's not at the end of the video.

Joseph Cho
  • 4,033
  • 4
  • 26
  • 33
gedas
  • 21
  • 2