I'm working on a kind of stopwatch/alarm, that's supposed to be running on a website using a modified wordpress plugin. It's function will later be, to start the stopwatch, and once it reaches 15 minutes, there will be an alarm sound. If the watch then doesn't get reset within the next 3 minutes, there will be another action (notification or something, not important right now, that part I already figured out), and if it's reset, it starts the whole thing again (will run for multiple hours).
I've set up the infrastructure via wordpress, and now my only problem is the stopwatch itself.
My problem right now is, that it "kind of" stops running, whenever someone moves to another tab or program. With "kind of", I mean: If the alarm sound was played ONCE, and I then reset it, it keeps counting even when switching tab after that. But on the first page refresh, it doesn't; except sometimes it does, but very slowly (1 "second" takes 3 real seconds). This is what my code looks like right now:
var silence = new Audio('exampleSilence.mp3'); //Audio-file with no content (so just silence)
var audio = new Audio('exampleAlarm.mp3'); //Audio-file with random song/alarm sound
var time=0;
var running=0;
function strtpause () { //Function responsible for start/pause button
if(running==0){
running=1;
increment();
document.getElementById("strtpause").innerHTML="Pause"
}
else{
running=0;
document.getElementById("strtpause").innerHTML="Resume"
return;
}
}
function reset(){ //Function responsible for resetting the stopwatch timer. At first also stopped
//the counting, but I disabled that part as I want it to keep going
//running=0;
time=0; //Sets time back to 0, so timer can start from 0 again
//document.getElementById("strtpause").innerHTML="Start"
document.getElementById("output").innerHTML="00:00"
audio.pause(); //Will also stop the alarm
audio.currentTime = 0; //And set the alarm time back to 0
}
function increment(){ //The actual stopwatch timer function
if(running==1){
setTimeout(function(){
time++;
var mins=Math.floor(time/60);
var secs=Math.floor((time)-(mins*60));
if(mins<10){
mins="0"+mins;
}
if(secs<10){
secs="0"+secs;
}
document.getElementById("output").innerHTML=mins+":"+secs;
if(1<time<9){ //I attempted to play a silent audio file in the background
silence.play(); //to keep the process running, but didn't have an effect
}
if(1<time<9){ //Also tried playing the audio file but very very silent.
audio.volume = 0.001; //It did work, but made timer go slower than regular seconds
audio.play();
}
if (time>10){ //Once the timer reaches a certain time, the alarm is played
audio.volume = 0.5; //Adjusts sound volume
audio.play();
}
increment();
},1000);
}
}
My solution ideas until now were:
-Change the setTimeout increments -> No effect, except with smaller increments it seemed to go slower
-Let it play a "silent" audio file with no actual sound content, so it "has something to do" (no idea if that makes sense, but audio files keep playing in background)
-Let it play an audio file with content while waiting, but very quietly (volume = 0.001). Did work, but made the stopwatch go way too slow, with 1 "second" = 3 actual seconds.
Ideas on how to keep the code running on any OS/Browser are appreciated! I'd prefer not to write/setup a different file or language, as my webdevelopment skills are very very basic, and I don't have rights to edit everything on the website.
Time delay for setTimeout() / setInterval() methods executing on inactive browser tabs are set to one second regardless of their value defined in code.
More about that here: https://usefulangle.com/post/280/settimeout-setinterval-on-inactive-tab
Related
The situation is like this - I have two videos, positioned on top of each other. These videos are almost the same (content wise), when you enter the page, video 1 starts playing. There is also a button, which when pressed should sync the second video to the first one and slowly fadeIn (it's hidden at first).
The problem I am having is with the syncing, when I try to set the currentTime of the second video, the player obviously first buffers some frames and after that starts playing, causing desync. I also tried some syncing timeouts with setting currentTime each 10ms until the second video's readyState turns to 4, but that causes pretty big delay.
The code I am using so far:
function switchVideo(first, second) {
var currentTime = first.currentTime;
second.pause();
second.currentTime = currentTime;
second.play();
syncAllowed = true;
var videoInterval = setInterval(function() {
if(next.readyState >= 4) {
second.addClass('show');
syncAllowed = false;
setTimeout(function() {
first.pause();
}, 500);
clearInterval(videoInterval);
}
}, 100);
}
var syncVideos = setInterval(function() {
if(syncAllowed) {
second.currentTime = first.currentTime;
}
}, 10);
So the question is, is there any way to sync one video to another one that is already playing, without having too much delay for the first video to get enought data for playing after setting it's current time? Also I noticed that there is a little bit of lag going backwards in time, which is weird, because that portion of video should already be buffered.
Thanks for any tips!
Thank you for looking at my question. Fiddle is HERE.
I am trying to implement an audio player for many songs on a page. This is using JQueryUI Slider and HTML5 Audio, with one Audio element and multiple sliders.
The problems right now are:
The slider does not animate with the audio.
The slider does not seek to the audio.
previously, when both of the above WERE working, once you chose a spot in the song, the slider would no longer animate.
I have created function to rebindSlider() when a new song is clicked. Inside this function, two things happen: a) the new slider is created, with slide and stop listeners defined, and b) the new slider is bound to the timeupdate event on the audio element for the new song. I feel like this should be all that I need, but the slider does not bind, and an undefined error can be seen when you try to drag the slider.
Using a single slider, and a single audio element, I have gotten this 90% the way there; as soon as I introduced multiple divs for the sliders though, problems started occurring.
Here is the code for rebindSlider:
function rebindSlider(sliderDiv) {
var createSeek = function() {
sliderDiv.slider({
value: 0,
step: 1,
orientation: "horizontal",
range: "min",
max: audioPlayer.duration,
animate: true,
slide: function() {
manualSeek = true;
},
stop: function(e, ui) {
manualSeek = false;
audioPlayer.currentTime = ui.value;
}
});
};
createSeek();
$(audioPlayer).bind('timeupdate', function() {
if (!manualSeek) {
sliderDiv.slider('value', audioPlayer.currentTime);
}
});
}
Further description is below.
There is a list of songs included on the page. Each song has a containing div, within which is an <a> that contains meta data (absent in the fiddle), as well as a div designated for the audio seek slider. There is a single audio element on the page, which has its source re-loaded as you click through the songs.
When a song is clicked, I would like to destroy the sliders bound to the playing audio (if necessary), and bind the new slider for the clicked song to the audio player.
The closest I have gotten was to have the slider 1) begin animating when the song plays 2) dragging of the slider moved to a different position in the song. Once the slider had moved though, it no longer animated. After a refactor, the slider no longer works, and though I could go to a previous commit to get the working code, the refactor was so drastic that I would prefer to present the current, non-working code, as it better represents what I would like to end up with.
Reasoning, and additional information.
I am making a web app, for which I have a concept for an audio player that I would rather build myself than modify anything that I have come across. That being said, if you know of something that I can implement, I would love suggestions.
The idea sounds simple enough, and most of it is done, but there is a very crucial part of it that I am having trouble with, which is setting up the slider to animate with, and seek to the desired spot in the audio track, and to be able to rebind a new slider to the audio when a song is clicked.
There are a few changes needed to get the slider working correctly. I'll cover them each, in order that they apply.
Invalid Slider Max Value
The first issue is that the slider's max value is set to the audioPlayer.duration, which would normally be all well and good, except that the HTML5 audio player loads the audio assets asynchronously. What this means is that even though you might have loaded the audio prior to setting the slider, the audio asset may not be loaded yet, and the audioPlayer.duration may be invalid (likely NaN).
Simply remove the max key (and value) from the slider initialization, and this will work. Et viola! The slider moves!
One caveat: the slider defaults to a max value of 100 units, and the duration of the audio is a little over 25 seconds, so the song finishes playing when the slider is 1/4th of the way along. We can set the max key to 25 (seconds), but that's a little inelegant, and wont work if we change the audio to use a different source.
Set the Slider Max Value
Capturing the audioPlayer.duration must be done be handling an event, once the asynchronous load has completed. Javascript provides such an event: onloadedmetadata. Let's install an event handler, and make this work:
audioPlayer.onloadedmetadata = function() {
$(".slider").slider("option", { max: Math.floor(audioPlayer.duration) });
};
Now, what this does is set the slider's max to the audioPlayer.duration once the audio asset has loaded. Actually, this is currently setting the max value for ALL of the sliders, but that shouldn't be a problem, since they're all hidden. If you have a very large number of songs, there might be a bit of a delay, and you may want to find the specific slider to update.
Smooth Sliding
Now, you may notice after these changes that the slider is somewhat jumpy. It pauses for a second, then jumps, then pauses, etc. This can be fixed very easily, by changing the step key to 0.1 in the slider initialization, like so:
sliderDiv.slider({
value: 0,
step: 0.1,
orientation: "horizontal",
The time updates occur every 50 to 250 milliseconds, but the slider could only move in 1-second increments. Now, with 1/10th of a second increments, the slider will move more smoothly. You can decrease that slightly if you like, but don't make the number too small; 0.01 is the practical lower bound.
Update the End-of-Play State
When the song has finished, the "Play" button is left in play state, even though there's no longer anything playing. There's an event for that, as well: onended. We'll use that event to update the UI, so that the user doesn't get confused:
audioPlayer.onended = function() {
playButton.removeClass('fa-pause-circle-o');
playButton.addClass('fa-play-circle-o');
};
Now, when the song finishes, the Play button will go back to the "play" state, and the user will know that clicking on it will play the song.
Refactor Play Button State
Since there are now 3 places that update the state of the Play button, and this involves duplication, we can refactor the state handling. This function will definitively set the state of the Play button:
function setUIState() {
if (audioPlayer.paused || audioPlayer.ended) {
playButton.removeClass('fa-pause-circle-o');
playButton.addClass('fa-play-circle-o');
} else {
playButton.removeClass('fa-play-circle-o');
playButton.addClass('fa-pause-circle-o');
}
}
Now, calling it from the other functions, you end up with the onended event handler:
audioPlayer.onended = function() {
setUIState();
};
The changeUI function:
function changeUI(selectedSong) {
setUIState();
var sliderDiv = selectedSong.parent().find('.slider');
rebindSlider(sliderDiv);//Bind the desired slider
$('.slider').hide(); //Hide all sliders
sliderDiv.show();//Show only the desired slider
}
And, the Play button click handler:
$(".playButton").click(function() {
if (audioLoaded === true) {
if (!audioPlayer.paused) {
audioPlayer.pause();
} else {
audioPlayer.play();
}
setUIState();
} else {
alert("Please click a song");
}
return false;
});
This makes the UI state management for the button simple to deal with, and keeps the state from creeping out through the app. You can already see how the refactored code is noticeable clearer and will be easier to maintain. Plus, as a bonus, we got to use the cool audioPlayer.ended attribute, which you don't see used much.
But Wait, There's More!
With the changes above, you're well on your way to having a very functional audio player. But that's certainly not the end of the line for feature functionality. There's always room to grow!
I've create a jsFiddle that includes all of these changes, as well as a few other mods to the original code. You can find the most recent version at: https://jsfiddle.net/mgaskill/mp087adp/. Additional features are likely to keep popping up, but the jsFiddle already includes these additional features:
Volume control (slider)
Time display
Dynamically generated HTML for audio controls (keeps the HTML simpler)
On a .js page in a Visual Studio express ASP.NET solution
why does
window.onload() {
document.getElementById('ambience').play();
}
work(and it does!), but why does
window.onload() {
document.getElementById('ambience').play();
document.getElementById('ambience').stop();
}
NOT stop the music? .pause(); doesn't pause the music either
I also tried:
It does play the music. And I have tried:
window.onload = function() {
var snd = document.getElementById('ambience').play();
var clickmeButton = document.getElementById('playJackpot');
clickmeButton.onclick = playSound;
}
function playSound() {
document.getElementById('ambience').stop();
}
what is the equivalent of .stop() or .pause() if those are not applicable? what set of commands
should I be working with in visual studio in order to get sound to play based on a conditional and then definitively shut off or stop after it has played once, and only once ? The background to this is that I have the play button in a timer control, so that it can operate other features, but each timer tick (and that needs to be set at a fraction of a second) kicks off the play again, so that the sound comes out staccato, because it is starting with every 'tick' of the timer. So, I need to play it, then immediately shut off the sound's ability to play, that is until somebody hits the play button again.
I'm in the frustrating situation of having an intermittent error. When functional, PHP specifies a video and 3 pictures to be displayed. The video begins playing 800ms after the page loads, and the pictures are displayed immediately upon the end of the video, at which point a user presses a key (corresponding to the location of the picture) and the keypress triggers a function that measures reaction time, stores which picture they selected, and loads the next page, whereupon all of this happens again with a new video and new pictures.
That all works just fine... sometimes.
At other times, I get a blank screen where I was expecting to see the video. Sometimes it happens right away, sometimes after as many as 15 or 20 successful loads, or anywhere in between. I'm running Chrome 27.0.1453.93, and tracking errors using Chrome's built-in javascript console. Even when the video fails to load, there are no javascript errors (with DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN">).
To pinpoint where things are breaking down, I've added a bunch of event listeners and used anonymous functions to pass some output to the js console log file to see which stages of the video event are or aren't happening. Here, at least, is a reliable pattern: every time the video fails to load, loadstart has happened, but durationchange has not. I just can't figure out what the problem is that prevents it from continuing!
I look forward to the responses here, whether they're answers or even just other people corroborating the experience so I don't feel so crazy! I'll include the two most relevant javascript functions here, but I'm not sure how much good they'll do.
<script>
function playVid(newSource){
console.log("playVid worked");
setTimeout(function(){//tells it to wait for some amount of time (below) before doing the next part
console.log("setTimeout was called");
document.getElementById("StimClip").innerHTML="<video id='video1'> <source src='" + newSource + "' type='video/mp4'>Something went wrong. Sorry 'bout that!</video>"; //replace blank.jpg with the appropriate video
console.log("the inner html was set");
myAddListener();
console.log("myAddListener was called");
var myVid=document.getElementById("StimClip"); //create a new variable to identify the video
console.log("the myVid variable was created");
video1.play(); //play the video
} //
,800); //finishes the setTimeout call by specifying how many msec to wait before executing.
}
function myAddListener(){
console.log("myAddListener worked");
var myVideo = document.getElementsByTagName('video')[0];
myVideo.addEventListener('waiting', function(){console.log("I'm WAITING...!")}, false);
myVideo.addEventListener('suspend', function(){console.log("Nice suspenders.")}, false);
myVideo.addEventListener('abort', function(){console.log("video was aborted")}, false);
myVideo.addEventListener('error', function(){console.log("there was an error")}, false);
myVideo.addEventListener('loadstart', function(){console.log("load start worked")}, false);
myVideo.addEventListener('durationchange', function(){console.log("the duration changed")}, false);
myVideo.addEventListener('loadedmetadata', function(){console.log("metadata was loaded")}, false);
myVideo.addEventListener('loadeddata', function(){console.log("data was loaded")}, false);
myVideo.addEventListener('progress', function(){console.log("progress...? ")}, false);
myVideo.addEventListener('canplay', function(){console.log("video can play")}, false);
myVideo.addEventListener('canplaythrough', function(){console.log("can play through worked")}, false);
myVideo.addEventListener('playing', function(){console.log("the video started playing")}, false);
myVideo.addEventListener('ended', ShowPics, false);
}
</script>
Oh geez. I'm glad no one else wasted their time trying to answer this. In case you were wondering, the thing that would cause a video to stop loading between loadstart and durationchange is if that video doesn't exist! (I had a typo in the filename of one of my videos, and because the order of videos is randomized I couldn't ever tell that it was always failing when it was trying to load the same one.)
Fixed.
We have a video (13 minutes long) which we would like to control using HTML5. We want to be able to let our users control and select the parts of the video they want to play. Preferably this control would be through 2 input fields. They would input start time (in seconds) in first box and input duration to play (in seconds) in second box. For example, they might want to start the video 10 seconds in and play for 15 seconds. Any suggestions or guidance on the Javascript needed to do this?
Note: I have found the following:
Start HTML5 video at a particular position when loading?
But it addresses only starting at a particular time, and nothing with playing the video for a specified length of time.
You could use the timeupdate event listener.
Save the start time and duration time to variable after loadedmetadata event.
// Set video element to variable
var video = document.getElementById('player1');
var videoStartTime = 0;
var durationTime = 0;
video.addEventListener('loadedmetadata', function() {
videoStartTime = 2;
durationTime = 4;
this.currentTime = videoStartTime;
}, false);
If current time is greater than start time plus duration, pauses the video.
video.addEventListener('timeupdate', function() {
if(this.currentTime > videoStartTime + durationTime){
this.pause();
}
});
If you are able to set start time and end time of video while setting the video url.
you can specify the start and end time in the url itself like
src="future technology_n.mp4#t=20,50"
it will play from 20th second to 50th second.
There are a lot of nuances to using the javascript solution proposed by Paul Sham. A much easier course of action is to use the Media Fragment URI Spec. It will allow you to specify a small segment of a larger audio or video file to play. To use it simply alter the source for the file you are streaming and add #t=start,end where start is the start time in seconds and end is the end time in seconds.
For example:
var start = document.getElementById('startInput').value;
var end = document.getElementById('endInput').value;
document.getElementById('videoPlayer').src = 'http://www.example.com/example.ogv#t='+start+','+end;
This will update the player to start the source video at the specified time and end at the specified time. Browser support for media fragments is also pretty good so it should work in any browser that supports HTML5.
Extend to michael hanon comments:
IE returns buffered.length = 0 and seekable.length = 0. Video doesn't play. So solution:
src="video.mp4#t=10,30"
will not works in IE. If you would like to support IE only way is to use javascript to seek video just after start from 0 second.