55

How does one force an abort event on an HTML5 video? I have an overlay, where, when I close it, the video should pause playing and then stop buffering. However, my internet connection continues to go nuts. Oh, I'm using Chrome 7.0.5 on Mac OS X 10.6.

I've tried a couple of things -- none of them have worked:

(For those unfamiliar with XUI, x$ is like the jQuery wrapping function)

First, dispatching an abort HTML Event:

var videoEl = x$('#video_el')[0];
videoEl.pause();
var evObj = document.createEvent('HTMLEvents');
evObj.initEvent('abort', false, false);
videoEl.dispatchEvent(evObj);

Next, changing the src and then forcing a load:

var videoEl = x$('#video_el')[0];
videoEl.pause();
videoEl.src = "";
videoEl.load(); //tried with and without this step

EDIT: My video element looks something like this:

<video id="video_el" src="<video_url>" preload="none" controls="controls" />

Again, none of these work. Anyone ran into this problem before? Any suggestions?

In summary, I am trying to force an HTML5 video element to stop buffering.

Thanks!

Brad Swerdfeger
  • 911
  • 1
  • 8
  • 11

5 Answers5

64

Ok, so for the last few day's I've really been struggling with this issue.
Here is my analysis and solution:

In short the problem I tried to solve:
I noticed that the HTML5 player does not stop downloading when the player is paused (at all, not even after a reasonable amount of time). Working with a 24/7 audio stream and developing a mobile website I realized that this is far from optimal for my visitors considering the high data usage if they leave the site open - although I do think I would make some telco's very happy by "overlooking" this issue...
Just to clarify, I don't really care about files with a fixed length. Downloading the complete file is most of the time a functionality required for viewing online resources (think slow connection) so not something I tried to prevent.

Analysis:
The HTML5 audio element does not have a stop() function, nor does it have an option where you can set the amount of data that it is allowed to buffer, or a way of saying you want the element to stop buffering - Don't confuse this with the 'preload' function, this only applies to the element before the play button is clicked.
I have no clue why this is and why this functionality is not available. If anyone can explain to me why these crucial functions are not implemented in a standard that should make web development for mobile phones better and more standardized I would love to know.

Solution:
The only working solution I found to implement a (sort of) stop function in your audio element is as follows:
1. Pause the current player - you can hook the pause event on the player via audio.addEventListener('pause', yourFunction);
2. Set the source to empty - audio.src = "";
3. Load the src - audio.load();
4. Remove the whole audio element
5. Insert a new HTML5 audio element without the source defined
6. Set the source (the source that was there in the first place) - audio.src = "old source url
7. Rehook the pause event - audio.addEventListener('pause', current-function);

Completely injecting a new HTML5 audio player is necessary for iOS. Simply resetting the src and then loading it causes the player to 'autoplay' in my case...

For the lazy people (includes jQuery):

var audio = $("audio").get(0);
audio.pause(0);
var tmp = audio.src;
audio.src = "";
audio.load();
$("audio").remove();

$("#audio-player").html("<audio controls preload='none'></audio>");<br>
audio = $("audio").get(0);
audio.src = tmp;
audio.addEventListener('pause', current-function);

Pressing pause will cause your visitor to lose there current location in the audio/video file and it will start again. I have no solution for this issue. Then again, if you are dealing with a live stream this solution should be fine.

Hope this helps.

Ruben
  • 1,427
  • 3
  • 17
  • 25
  • 6
    Why don't you just store the current time on a temporary variable, and when the user clicks on the play button, you set the audio player to that value? – franzlorenzon Jan 27 '13 at 14:58
  • 3
    You can indeed do that, but I developed this to unload a live stream. Pickup up a live stream at the point where you pressed stop is a bit pointless ;) But for very large files that is definitely a very good point I can add. – Ruben Jan 28 '13 at 08:02
  • 1
    This is a bad solution, as it will throw 'error' events in attempt to load current webpage (i.e. http://127.0.0.1), which generates additional artificial load. I've tried `null` and `undefined` but those just add to path of current page. If you don't care about errors it makes more sense to use `src="about:blank"`. – Artur Bodera Mar 27 '14 at 15:06
  • @ArturBodera this is the only solution. The error is an unfortunate side effect of the player not supporting any 'stop' functions. That is why unloading the resource is required. Until the HTML5 audio element supports this function I suggested this as a workaround. Not as a permanent solutions. And the problem your describing can simply be solved by putting a `try catch` around the line that is throwing the error. – Ruben Mar 27 '14 at 23:45
  • @Ruben `try catch` doesn't help with anything because it's throwing an error event. The biggest issue is the browser trying to load `http://current.web.page` as a media! This means your "solution" can be harmful, unless you direct the browser to something like `about:blank` - which is still clunky, but at least doesn't generate bogus requests to web srv. – Artur Bodera Mar 28 '14 at 08:35
  • 2
    @ArturBodera your indeed right. The try catch does not work. I'll add the about:blank to the original post. I had a quick look, and the error only happens in FF not in Chrome. As far as I can see both browsers "accept" different methods. FF is happy if you simply reload (use the same resource). This will stop the browser for downloading the resource. Chrome doesn't mind the empty resource. Haven't tested other browsers but I'll add these notes. Thanks for you comment. – Ruben Apr 07 '14 at 00:15
  • It has been a really long time since I've worked with this code base, but based on the feedback, I'll mark this as a correct answer for now :) – Brad Swerdfeger Apr 14 '14 at 19:37
  • @franzlorenzon In newer browsers, you can now use [Media Fragments](https://www.w3.org/TR/media-frags/#media-fragment-syntax) to load straight to the target timepoint, eg. http://www.example.org/video.ogv?t=60,100#t=20 starts your media player 20s into a fragment that shows the period of 60s to 100s in the original file (ie. a fragment that is 40s long). This allows you to update the time value without a callback of any sort. – Jamie Birch Jun 21 '17 at 16:51
14

With preload="none", This is how I force aborted the buffering after pausing the video, and then resumed playback at the paused location using jQuery.

<video id="video_el" src="<video_url>" preload="none" controls="controls" />    

<script>
jQuery(function() {

  var video = jQuery('video').get(0);

  video.addEventListener('pause',function(){
     var tmp_src = video.src;
     var playtime = video.currentTime;
     video.src = '';
     video.load();
     video.src = tmp_src;
     video.currentTime = playtime;
  });

});
</script>
Eric Leroy
  • 1,830
  • 1
  • 18
  • 31
1

The key step seems to be to not set src to a blank value before calling load(). I've had success doing it like this:

var wasPlaying = !audioPlayer.paused;
audioPlayer.currentTime = 0.0; // Optional -- can be left out for pause
audioPlayer.pause();

if (wasPlaying) { // This prevents the browser from trying to load the entire source
    audioPlayer.load();
}

In both Chrome and Firefox on Win10, this fires an abort event. In my specific case this was required to close the sockets that would otherwise remain open indefinitely, which led to hitting the six connections per server limit with multiple players being used on the same page.

mnille
  • 1,328
  • 4
  • 16
  • 20
Dinfinity
  • 11
  • 1
0

Actually you can do the same thing by setting the src attribute as a php/aspx file with some params to read the file content and retrieve the data as the equivalent type(e.g., Content-Type: video/mp4). BUT it does't work in IE 11 (what a surprise :D), then you'll need to do the trick above just for this gorgeous browser.

Use this...

<video id="v1" preload="none">
  <source src="video.php?id=24" type="video/mp4">
</video>

Instead of this...

<video id="v2" preload="none">
  <source src="video-24.mp4" type="video/mp4">
</video>

As a drawback you won't be able to determine the full length of the video, but to solve this problem, that's not soo big, you could store this value in your database or just make another little trick.

I've tested using Chrome 32, Firefox 26, Opera 18 and IE 11 the following script

setInterval(function() {
    var r = [];

    try {
        r.push(v1.buffered.end(0));
    } catch(e) {
        r.push('nahh');
    };

    try {
        r.push(v2.buffered.end(0));
    } catch(e) {
        r.push('second nahh');
    };

    console.log(r.join(', '));
}, 500);

In my localhosts tests...

Firefox 26 After you had pressed play, it ALWAYS buffered the full file.

IE 11 (considering src="video-24.mp4", cuz the other don't work) After you had pressed play, it ALWAYS buffered the file chunk by chunk even if it was paused and completly ignores the preload="none" attribute.

Chrome 32 Works perfectly (same for Opera 18).

0

You could also change the src to a mp3 that contains one second of silence. Than call the play function with the new src. As the new mp3 is loaded the buffering of the stream stops.

var audio = document.getElementById("audioradio");
audio.src = "/sound/pause.mp3";
audio.play();
<audio style="display: none;" id="audioradio" src="/sound/pause.mp3" preload="none"></audio>

Testet in Firefox only!

IchEben
  • 35
  • 1
  • 4