setinterval function using previous/ old value for a variable - javascript

I want to play portion of video (html5) and loop through those portions on "onclick" of 2 textareas. I am passing starttime (st) and endtime (et) to the javascript function.
textarea1 : st=6 et=12
textarea2 : st=15 et=20
I am using setinterval to check the endtime and calling method again to loop.
scenario :
Click on textarea1. st=6 et=12. While it is playing click on textarea2. The condition video.currentTime > et is true as 15 > 12 which is wrong result. The et value is not changing on "onclick". Please help.
Here is my code:
function playVideo(st,et) {
var video = document.getElementById('player');
video.currentTime = st;
video.play();
int = setInterval(function() {
if (video.currentTime > et) { // here the et still has the previous value
playVideo(st,et); // loop
}
}, 10);
}
<video width="320" height="240" controls="controls" id="player">
<source src="abc.mp4" type="video/mp4" />
</video>
<textarea onclick="playVideo(6,12)" >Part1 </textarea>
<textarea onclick="playVideo(15,20)">Part2</textarea>

It's not that et has the previous value, it's that you're never getting rid of the old interval.
Instead of calling playVideo again, you would be better off just calling video.currentTime = st;. However, bear in mind that you will need something that stops the interval. Personally, I'd do something like this:
function playVideo(st,et) {
var video = document.getElementById('player');
clearInterval(arguments.callee.interval);
video.currentTime = st;
video.play();
arguments.callee.interval = setInterval(function() {
if( video.currentTime > et) video.currentTime = st;
},10);
}
I'm saving the interval as a property of the function, which is essentially JS's equivalent to static variables. This way, when the user clicks on the other textarea it will clear out the existing interval to ensure it doesn't interfere anymore.

Get rid of your old interval by using clearInterval!

Your problem might be that you're not clearing the interval callback. Try checking for a previous (but still active) interval, and clearing it before assigning a new one.
var videoEndInterval = null;
function playVideo(st, et) {
...
if (videoEndInterval !== null) {
clearInterval(videoEndInterval);
}
videoEndInterval = setInterval(function() {
...
}, 10);
}

Your 'loop' currently creates each interval a new interval, and you get a mess of intervals. setInterval does execute every x ms, where setTimeout does execute once after x ms. You need to clear your interval, when you stop the video.
Try this:
// var declared outside, to clear an old interval,
// but also to not have a global variable.
var stopInterval;
var playVideo = function (st, et) {
var video = document.getElementById('player');
video.currentTime = st;
video.play();
if (stopInterval) {
// clear an old interval, if playVideo is called twice
window.clearInterval(stopInterval);
stopInterval = 0;
}
stopInterval = window.setInterval(function() {
if (video.currentTime > et) {
// here your video is after et, so clear the interval and stop.
window.clearInterval(stopInterval);
stopInterval = 0;
video.pause();
}
}, 10);
};
You should also hint if your video isn't buffered, is not playable and is paused (to clear your interval).
See also
HTMLVideoElement Interface, HTMLMediaElement Interface,
video HTML5 element, and
Using HTML5 audio and video on Mozilla's Developer Network.

Related

Most accurate video pause on Earth (currentTime Vs mediaTime And requestVideoFrameCallback Vs setInterval)

Let's say we want to try our best to create the most accurate video pause function based on the given point (of time) of the video element.
So we try this to experiment:
var vid = document.getElementById("myVideo");
Method1();
Method2();
function Method1() {
const doSomethingWithTheFrame = (now, metadata) => {
// Do something with the frame.
console.log(vid.currentTime, now, metadata);
if(metadata.mediaTime >= 0.5) {
console.log("Method1 Executed Here", vid.currentTime, metadata.mediaTime);
vid.pause(); // reached 0.5 so stop the video
return;
}
// Re-register the callback to be notified about the next frame.
vid.requestVideoFrameCallback(doSomethingWithTheFrame);
};
// Initially register the callback to be notified about the first frame.
vid.requestVideoFrameCallback(doSomethingWithTheFrame);
}
function Method2() {
const endCheck = setInterval(endCheckInterval, 5);
function endCheckInterval() {
if (vid.currentTime >= 0.5) {
clearInterval(endCheck);
console.log("Method2 Executed Here", vid.currentTime);
//vid.pause(); // reached 0.5 so stop the video
}
}
}
<!DOCTYPE html>
<html>
<body>
<video id="myVideo" width="320" height="176" controls>
<source src="https://www.w3schools.com/tags/mov_bbb.mp4" type="video/mp4">
</video>
</body>
</html>
As you see I compared vid.currentTime Vs metadata.mediaTime and there is a little difference between the two...
Which one should we use for reliability and accurate pausing at the 0.5 second of the video?
In Chromium's implementation, we use the audio clock as the time source that backs video.currentTime, whereas the mediaTime is directly populated by the presentationTimestamp of the frame. The mediaTime is what you should use if you want to exactly identify frames in a reproducible way, including to identify exactly which frames you missed.

HTML5 audio on IOS: how can currentTime be less than initial value?

I have to play a short fragment of bigger audio. I use currentTime to set starting point in time, and timeupdate event to stop audio when required.
I noticed that on few early timeupdate events sometimes currentTime is less than its initial value, despite there is (obviously) no "rewind" actions.
Here is code example:
var start = 1;
var end = 1.3;
var audio = document.getElementById('audio');
audio.addEventListener('timeupdate', function () {
console.log(audio.currentTime);
if (audio.currentTime < start || audio.currentTime > end) {
audio.pause();
}
});
audio.currentTime = start;
audio.play();
For example, output of console log can be this:
1
0.85
0.85
1
1.02
...
Here's an example.
Tested on iPad with iOS 11.4.1. This problem appears only on very short time ranges ~0.3sec.
At first you have a wrong question because you want that your script works on iOS. And because of this your question in title is irrelevant. We have a lot of bugs on iOS and the iOS developers do not want to correct them. It is a bug. Write to support from iOS and ask there "How is it possible?".
At second you have two questions in your post because your script does not work on iOS like you it want.
I wrote for you the solution. Make sure you are not trying to call the audio before the audio element has metadata loaded (first mistake). Then you have the second mistake: instead of:
if(audio.currentTime < start || audio.currentTime > end) //your mistake
you have to write:
if(audio.currentTime >= end)
The solution (it works on iOS too)
var start = 1,
end = 1.3,
audio = document.getElementById('audio'),
button = document.getElementById('button'),
log = document.getElementById('log');
audio.addEventListener('timeupdate', function()
{
writeLog(audio.currentTime);
//your mistake: if(audio.currentTime < start || audio.currentTime > end)
if(audio.currentTime >= end)
{
audio.pause();
}
});
function writeLog(value)
{
var div = document.createElement('div');
div.innerHTML = value;
log.insertBefore(div, log.firstChild);
}
audio.addEventListener('loadedmetadata', function()
{
audio.pause();
button.removeAttribute('disabled');
});
button.addEventListener('click', function()
{
log.insertBefore(log.lastChild.cloneNode(!0), log.firstChild);
audio.currentTime = start;
audio.play();
});
#log
{
width:100%;
height:18em;
overflow-y:auto;
font:3em 'Courier New';
background:#069;
color:#7e0
}
#log div:last-child{display:none}
<!--
For this link from your example (on jsfiddle.net) is only a download is possible, but not using as source:
http://techslides.com/demos/samples/sample.m4a
-->
<audio id="audio" preload="auto">
<source src="http://techslides.com/demos/samples/sample.mp3" type="audio/mpeg"/>
<source src="http://techslides.com/demos/samples/sample.ogg" type="audio/ogg"/>
<source src="http://techslides.com/demos/samples/sample.aac" type="audio/aac"/>
</audio>
<button id="button" disabled style="width:9em;height:3em;font-size:3em">Play</button>
<br><br>
<div id="log"><div><hr></div></div>
The snippet on SO does not work because it is in sandbox.
See this working example on codepen.io.

Is it possible to embed actions in html5 video?

Is there any way to play a video in html5, stop and execute javascript at known points within the video?
Yes, try this. You have to use the currentTime property. Start with that and start your javascript functions from there. Is that what you're looking for?
var vid = document.getElementById("video");
//Add a timeupdate listener
video.addEventListener("timeupdate", function(){
//Check for video properties from within the function
if (this.currentTime == 5)
this.pause();
//cal javascript
}
}
Looking at the accepted answer over here it looks like it is possible.
To pause the video you just do this:
var mediaElement = document.getElementById("video"); // create a reference to your HTML5 video
mediaElement.pause(); // pauses the video
If you want to play the video, do this:
mediaElement.play(); // plays the video
To get the current time in the video, do this:
mediaElement.currentTime; // gets the current time
Here's an example linking them all up:
var mediaElement = document.getElementById("video");
if(mediaElement.currentTime == 35){
mediaElement.pause();
// do whatever else you would like
mediaElement.play();
}
The MDL documentation is here, there are plenty of other properties you might find helpful.
Hope this helps!
Yes, by doing like this you can.
Note that you have to look for a time using bigger than > bigger than (as the chance to match an exact millisecond is almost zero), and have a variable in one way or the other to know which ones is done.
window.addEventListener('load', function() {
var cur = document.querySelector('#cur'),
vid = document.querySelector('#vid')
})
var appDone = {"done7":false,"done4":false}
vid.addEventListener('timeupdate', function(e) {
if (e.target.currentTime > 7 && !appDone.done7) {
appDone.done7 = true;
e.target.pause();
//do something
cur.textContent += ", " + "done7 once";
e.target.play();
}
if (e.target.currentTime > 4 && !appDone.done4) {
appDone.done4 = true;
e.target.pause();
//do something
cur.textContent += ", " + "done4 once";
e.target.play();
}
})
<video id="vid" width="320" height="176" controls>
<source src="http://www.w3schools.com/tags/mov_bbb.mp4" type="video/mp4">
<source src="http://www.w3schools.com/tags/mov_bbb.ogg" type="video/ogg">
Your browser does not support HTML5 video.
</video>
<p id="cur"></p>

Google Chrome, audio, setTimeout, replace audio src, restarts mid-audio

This is only an issue in Chrome and runs fine in the other browsers.
I click a speaker which plays a welcome message, if the welcome message is not finished, I keep checking until it is finished, then I change the source to another message.
If I then click the speaker again to hear the new message, this message starts and after a few seconds stops and starts again, then stops (my estimate is that it stops when the duration of that message is passed)
In my html:
<audio id="shop_audio" preload="auto" type="audio/mpeg" src="/audios/helper/shop/en/welcome.mp3"></audio>
<p id="shop_speaker">
<i class="fa fa-volume-up"></i>
</p>
In my javascript:
Doc ready:
$("#shop_speaker").click(function(){
document.getElementById("shop_audio").play();
});
Then:
$(window).load(function(){
sl.utils.t_shopInstructions = setTimeout(sl.shop.audio.setAudio, 5000, 0);
});
And:
sl.shop.audio={
setAudio: function(which){
clearTimeout(sl.utils.t_shopInstructions);
var audio = document.getElementById("shop_audio");
if(audio.paused==true){
sl.shop.audio.newSrc(which);
}else{
sl.utils.t_shopAudioPlaying = setInterval(sl.shop.audio.waitForPaused, 500, which);
}
},
waitForPaused: function(which){
if(document.getElementById("shop_audio").paused==true){
clearInterval(sl.utils.t_shopAudioPlaying);
sl.shop.audio.newSrc(which);
}
},
newSrc: function(which){
document.getElementById("shop_audio").src = '/audios/helper/shop/en/help_instruction_'+which+'.mp3';
}
}
And a variant that also works everywhere, except chrome:
(I thought that setInterval was causing trouble, and/or its clearing)
sl.shop.audio={
setAudio: function(which){
clearTimeout(sl.utils.t_shopInstructions);
var audio = document.getElementById("shop_audio");
if(audio.paused==true){
sl.shop.audio.newSrc(which);
}else{
(function looping(){
clearTimeout(sl.utils.t_shopAudioPlaying);
if(audio.paused==false){
sl.utils.t_shopAudioPlaying=setTimeout(looping, 500);
}else{
sl.shop.audio.newSrc(which);
}
})()
}
},
newSrc: function(which){
document.getElementById("shop_audio").src = '/audios/helper/shop/en/help_instruction_'+which+'.mp3';
}
}
Placing the clearTimeout() in different places makes a difference, so I pursued that, but the result is not consistent.
I have now removed all the clearTimeouts - they make no difference whatsoever. The problem stays exactly the same.
Thanks for your suggestions!
I click a speaker which plays a welcome message, if the welcome
message is not finished, I keep checking until it is finished, then I
change the source to another message.
You can substitute ended event for setTimeout. Since you are using jQuery use .one() instead of .click().
var audio = $("#shop_audio")[0];
var speaker = $("#shop_speaker");
function resetAudio() {
audio.play();
audio.onended = function() {
this.onended = null;
this.src = "/path/to/a/different/src";
speaker.one("click", resetAudio);
}
}
speaker.one("click", resetAudio);

Javascript Timers not consistent

I know there has been many topics on Javascript Timers however, my timers are in effect "Doubling" every time my mouse hovers over a div to call a command, they are not consistent.The divs below show the onmouseover event which calls the functions.
<div id="Team_Container2"><div id="Image1" onmouseover="area_hover1(this);area_hover2(this)"></div>
<div id="Team_Container2"><div id="Image2" onmouseover="area_hover1(this);area_hover2(this)"></div>
function area_hover1(obj) {
var interval;
clearInterval(interval);
href = $(obj).attr('href');
url = href.split('#');
url1 = url[1];
interval = setInterval(function() {setAreaOver(document.getElementById(url1), 'Seating_Plan_Image_canvas', '0,0,0', '0,0,0', '0.33', 0, 0, 0);}, 1000);
return;
}
function area_hover2(obj) {
var interval;
href = $(obj).attr('href');
url = href.split('#');
url1 = url[1];
clearInterval(interval);
interval = setInterval(function() {setAreaOver(document.getElementById(url1), 'Seating_Plan_Image_canvas', '0,0,0', '0,0,0', '0.0', 0, 0, 0);}, 2000);
return;
}
How could i adjust the timer or merge the two functions into one and perform one "setInterval" after the other one.
I need the area_hover2 set Interval to come like 500 milliseconds after the first Area_hover1 set interval if that makes sense.
Any help would be most appreciated!
Thanks
Aj
Every time you hover over your image, you kick off a new setInterval, since your clearInterval() command isn't really doing anything. You defined the variable holding the setInterval() pointer inside the hover function, so as soon as it exits, that variable is gone. What you need is:
var interval; // Defined in global scope
function area_hover1(obj) {
clearInterval(interval); // Abort any existing hover interval
// Set up variables
interval = setInterval(function() { /* doStuff */ }, 1000);
}
You may also need to capture the onMouseOut event to stop the interval as well, since right now it will keep running even after the mouse is no longer hovering over the element.

Categories