How to distinguish between two "onpause" events - caused by clicking “pause” button, and caused by reaching the end of a media fragment?

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
}