HTML5 video seeking to mid-video on 'ended' on Safari - javascript

I'm using a <video> for a background hero video. It starts at 0:00. When it reaches the end of the 0:11 clip, it pops back to :02 and repeats from there. I've accomplished it with:
document.getElementById('bgvid').addEventListener('ended',repeatVid,false);
function repeatVid(e) {
var mediaElement = document.getElementById('bgvid');
mediaElement.currentTime = 2;
mediaElement.play();
}
I'm only concerned with the desktop experience, since it swaps to a fallback image on tablet/mobile. This works with Chrome, Firefox, and even IE. Safari, however, repeats back from 0:00 instead of :02.
Putting the whole function on a button onclick instead of an addeventListener works. Reassigning currentTime doesn't appear to be the problem. I've tried putting the whole thing inside video.oncanplaythrough = function () {. I've tried changing the .addEventListener('ended') to $('video').on('ended',function(){ or video.onended = function () {.
It seems like .play() always sends you back to 0:00, except I can get it to work on('click'), so there's something up. Thanks for your help!

The play() function in Safari seems to reset the currentTime to zero.
If you play() the video and set the currentTime directly after that, it works like expected:
document.getElementById('bgvid').addEventListener('ended',repeatVid,false);
function repeatVid(e) {
var mediaElement = document.getElementById('bgvid');
mediaElement.play();
mediaElement.currentTime = 2;
}

Related

removeEventListener("timeUpdate", myFunction) is unstable during video play

An event listener is added once my video starts playing. That is
document.getElementById("myVideo").addEventListener("timeUpdate", myFunction);
and then just before the video ends I want something to happen (perhaps a fade out) along with the last few seconds of the video (or to keep things simple I'm just going to write something like alert("goodbye");) instead.
and when I use this piece of code
var myVideo = document.getElementById ("myVideo");
function myFunction(){
if(myVideo.currentTime >= (myVideo.duration-3) )
{
alert("this goodbye message is supposed to be displayed only once and exactly three seconds before the video ends");
myVideo.removeEventListener("timeupdate", myFunction);
}
}
it works in Chrome but it's unstable. Sometimes it works fine but other times the alert keeps popping a few times before the event listener is actually removed (which is bad in my case). In Firefox it is even worse as it fires many times.
I know that different browsers make timeupdate event fire at very different intervals.
So what do you think? Should I give up on the
addEventListener()
removeEventListener()
couple and use
setInterval()clearInterval() to check where the playhead is and do stuff when the time comes.
That way instead of browser dependent time intervals I could set my own time interval for consistency. But does anybody know if there is a reliable way to do this with timeUpdate?
I used a timer instead and now it works perfectly.
var checkThePlayheadPositionTenTimesASecond = setInterval(myTimer, 100);
function myTimer()
{
if(myVideo.currentTime >= (myVideo.duration-3) )
{
alert("this video is going to end in three seconds");
clearInterval(checkThePlayheadPositionTenTimesASecond);
}
}
Still I'm going to leave this post active in case anyone has to say anything.

HTML5 Audio Element Stops Playing

I would like use an HTML5 audio element such that it has multiple "channels." Normally, with a simple audio tag, if I press the play button once, it will play; however, if I press play again while the audio is still playing, it won't play the again. Essentially, I want the same sound to be able to be played again simultaneously unless all of the channels are playing.
To do this, I'm loading many audio tags. Here is my code to load the audio files:
function loadAllAudios(number) {
toLoad = number;
loaded = 0;
audios = [];
for (var i = 0; i < number; ++i) {
// Random test audio file here
loadAudio("http://www.w3schools.com/html/horse."); // Leave off extension
}
}
And the loadAudio function is as follows:
function loadAudio(source) {
var aud = document.createElement("audio");
aud.addEventListener("canplaythrough", function() {
++loaded;
});
aud.src = source + (aud.canPlayType("ogg") ? "ogg" : "mp3");
audios.push(aud);
};
To keep track of which audio element is playing, I have an array called audios. The elements at the beginning of the array have probably ended, while those at the end are probably still playing. When an audio element starts playing, it is moved from the beginning to the end.
This is the code that gets executed when you press play:
console.log(audios);
// Make sure everything is loaded, and that audios isn't an empty array
if (loaded === toLoad && audios && audios.length) {
var curAudio = audios[0];
curAudio.play();
// Move the first element to the end of the array
// so that we don't play it again while it is still playing
audios.push(audios.shift());
}
The jsfiddle is here: http://jsfiddle.net/prankol57/XgRH4/1/
My problem is that, for example, if I load three channels, after clicking play 4 times, the code stops working, even if all the audios have ended. I thought it might have been that the element isn't moved to the end correctly, but a console.log shows that all the audio elements are still there.
Edit: Of the browsers I tested in (Chrome, Firefox, and Internet Explorer 11), the code works only in Internet Explorer 11.
canplaythrough event will fire more than once for single file, causing unexpected ++loaded (even when the file was already loaded) and thus loaded === toLoad condition will return false.

HTML5 audio start over

Having
var audio = new Audio("click.ogg")
I play the click sound when needed by
audio.play()
However, sometimes user is so fast that a browser does not play the audio at all (probably when still playing a previous play request). Is this issue related to preload?
How can I force a browser to stop playing and start over? There is no stop, just pause in HTML5 audio component, correct? What workaround can be used here?
Update - Additional note:
I have multiple checkbox-like div elements with a touchend event. When such event is triggered, the elements visually change, a sound is played and an internal variable is set accordingly. If user tap on these elements slowly, everything works nicely. If tap fast, the sound is often completely skipped...
The simplest solution is to just reset the audio currentTime and ensure it's playing using the play() method. Checking if the audio is playing is not necessary as subsequent play() invocations will not do anything.
audio.currentTime = 0;
audio.play();
This is the code I've been using and it's working for me:
if(audioSupport.duration > 0 && !audioSupport.paused){
//already playing
audioSupport.pause();
audioSupport.currentTime = 0;
audioSupport.play();
}else{
//not playing
audioSupport.play();
}
I noticed that on Firefox, playing a sound again and again really fast (like a short ticking sound) will skip beats often. The best solution I got was to simply call cloneNode and play each sound that way. Its not perfect (compared to Chrome where it sounds flawless):
var audio = document.getElementById('myaudio');
setInterval(function() {
audio.cloneNode().play();
}, 100);
The only way i found how to play a short sound very quickly (so quick that the 2nd sound starts before the first ends) is to actually load 5 or 10 and if you have to play again but are already playing, just go to the next, which is not playing:
var soundEls = [];//load 10 audios instead of 1
for(var i=0;i<10;i++){
var soundEl = document.createElement('audio');
soundEl.src = url;
soundEl.preload = 'auto';
$(this._soundEl).append(soundEl);
soundEls.push(soundEl);
}
var soundElIndex = 0;
return {play:function(){
var soundEl = soundEls[soundElIndex];
if(soundEl.duration > 0 && !soundEl.paused){
//already playing, switch to next soundEl
soundElIndex++;
if(!soundEls[soundElIndex]) soundElIndex=0;
soundEls[soundElIndex].play();
}else{
//not playing
soundEl.play();
}
}};
Result of this is you can actually play the same sound over itself.
Probably not the right way to do it though.

recursive setTimeout() pause on background

I have a piece of code:
var logo = $("#blinking-logo");
function logo_blink() {
logo.fadeOut(10).delay(10)
.fadeIn(10).delay(20)
.fadeOut(10).delay(10)
.fadeIn(10)
window.setTimeout(logo_blink, (Math.random()*(1500))+1500);
}
logo_blink();
All it makes is blinking a picture once in ~30 seconds (time is less here for easier debugging)
The problem that Chrome pauses this timer while the tab in backgrounded, and then, when coming back to that tab, it blinks all the blinks that were missed in background.
I'd like to pause the timer while in background, but I don't know how. I've read some related posts, but it seems that they describe the opposite problem. Is there any way to detect the backgrounding of a tab?
It is a known feature. To conserve the resources Chrome does not update the window without focus :) You could check, for example, that window lost its focus and stop the timer. Start it again when window is in focus. For example:
var timer = null;
var logo = $("#blinking-logo");
function logo_blink() {
if(timer) clearTimeout('timer');
logo.fadeOut(10).delay(10)
.fadeIn(10).delay(20)
.fadeOut(10).delay(10)
.fadeIn(10)
timer = window.setTimeout(logo_blink, (Math.random()*(1500))+1500);
}
logo_blink();
$(window).blur(function(){clearTimeout(timer); timer = null;});
$(window).focus(function(){if (!timer) timer = window.setTimeout(logo_blink, (Math.random()*(1500))+1500);});
Something like this. On one of my pages with animation a had the same problem with setInterval, so I just pause it when the page is in background.
if (!$.browser.msie)
{
$(window).focus(function(){paused = false;});
$(window).blur(function(){paused = true;});
}
And than skipped animation based on the value of paused flag.
ps: Code is updated with optimization discussed below.
Chrome, Firefox and IE10 have page visibility APIs that you can use to determine when you page is no longer visible. This works better than using focus in some circumstances. Here's an example from MDN:
//startSimulation and pauseSimulation defined elsewhere
function handleVisibilityChange() {
if (document.hidden) {
pauseSimulation();
} else {
startSimulation();
}
}
document.addEventListener("visibilitychange", handleVisibilityChange, false);
And, some reference documents:
http://code.google.com/chrome/whitepapers/pagevisibility.html
https://developer.mozilla.org/en/DOM/Using_the_Page_Visibility_API
W3 Document: http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/PageVisibility/Overview.html
The only work-arounds I've seen for older browsers involve determining whether your window has focus or not which isn't perfect, but maybe better than nothing in some cases.

JWPlayer 4 javascript events are ignored

First of all, I can't upgrade to a newer version of the player, because I need the displayclick=fullscreen option to work, and it doesn't with version 5.
So, what I need to do is this: have the player auto-start with no volume and no controls on the page (this works just fine), and when the user clicks the screen the player must go full-screen and the volume must turn on.
The problem is all Javascript interaction seems to be completely ignored by the player, and I really can't see where the problem is.
When the page is loaded, I embed the player:
var so = new SWFObject('path_to_player.swf','div_id','200','120','10');
so.addParam('allowfullscreen','true');
so.addParam('allowscriptaccess','sameDomain');
so.addParam('bgcolor','#000000');
so.addParam('flashvars','file=path_to_playlist.xml&autostart=true&displayclick=fullscreen&controlbar=none&volume=0&icons=false&image=path_to_thumb.jpg');
so.write('div_id');
This seems to work just fine, the player is loading.
Then I add the event listeners:
var player = null;
function playerReady(p) {
player = document.getElementById(p.id);
addListeners();
}
function addListeners() {
if (player) {
console.log('add the listener');
console.log(player.getConfig().volume);
player.addControllerListener("RESIZE", "checkResize");
} else {
setTimeout("addListeners()", 100);
}
}
function checkResize(obj) {
console.log('resized');
if (obj.fullscreen) {
player.sendEvent("VOLUME", "60");
} else {
player.sendEvent("VOLUME", 0);
}
}
The "add the listener" message gets displayed in the console, but the second one, with the player's volume doesn't, and neither does the "resized" one when the player enters or exits fullscreen (and, obviously, the volume doesn't turn on).
I've tried other listeners, for both model and controller, and they don't seem to work. Sending events doesn't work either.
I've tried running just the code for the player separately, to make sure there are no other things interfering with the code, but I still have the same problem.
Well, it seems I've found the answer myself. Upgrading to a newer version of swfobject and using swfobject.embedSWF() seems to work just fine.

Categories

Resources