I want to play a sound after the countdown timer is done.
Normally I will do it using this peace of code
var audio = new Audio('path to file.mp3');
audio.play();
But I get the following error Unhandled Promise Rejection: NotAllowedError: The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.
The thing is ... Google it self is doing it using a HTML5 audio tag
If you type countdown timer into google search field it should show you the widget that plays a sound after the countdown timer is finished.
Here is how Googles timer look like, if you guys don't know what I'm talking about :)
By making you click this "START" button, they ask for an user gesture and thus have marked their document as approved-by-user to play audio. This means they are not subject for chrome's autoplay policies anymore.
Now, Safari by default is even stricter than Chrome here, and a simple click on the document doesn't work: in this browser you need to start the playback from the user-event itself.
So in your case, it won't work, even if you did start the countdown from a click like Google.
The solution is then to start the playback from the click event, and to pause it immediately after. Doing so, your Element will be marked as approved-by-user and you will ave full control over it.
const audio = new Audio("https://dl.dropboxusercontent.com/s/1cdwpm3gca9mlo0/kick.mp3");
let time = 5;
btn.onclick = e => {
// mark our audio element as approved by the user
audio.play().then(() => { // pause directly
audio.pause();
audio.currentTime = 0;
});
countdown();
btn.disabled = true;
};
function countdown() {
pre.textContent = --time;
if(time === 0) return onend();
setTimeout(countdown, 1000);
}
function onend() {
audio.play(); // now we're safe to play it
time = 5;
btn.disabled = false;
}
<button id="btn">start countdown</button><br>
<pre id="pre"></pre>
Related
Here is the link to code pen to my project https://codepen.io/RajTheSHow/pen/vZZPqZ
when you press the wrong button it is supposed to play the sequence(with audio and button press in order).however what actually happens is when you press the wrong button it plays all the audio and changes the color at once and doesn't execute what is in the sleep function.you can see the problem in the pen.
the function that runs the sequence when you press the wrong button is below
cal is where the order is stored of the sequence.
//plays the sequence
function callBut(){
onr=0;
for(i=0;i<cal.length;i++){
// or eval ("s"+cal[i])
window["s"+cal[i]].play();
// set the but# to Clicked Color Ccol# then after 1 sec go back to normal color
$("[but="+cal[i]+"]").css("background",window["Ccol"+cal[i]])
sleep(500).then(() => {
// set the button# to Standard color Scol#
$("[but="+cal[i]+"]").css("background",window["Scol"+cal[i]])
});
}
What'd you expect? The loop does not wait for the audio to finish. It's better to use recursion to play the next song.
let arr = cal.map(element => window[`s${element}`]); // asuming 'cal' is something significant
let index = 0;
playAudio(arr[index]);
function playAudio(audio) {
if (!audio || !(audio instanceof Audio)) return;
audio.addEventListener('ended', function() {
index++;
playAudio(arr[index]);
})
audio.play();
}
This is the correct and expected behaviour.
What you want to achieve requires to wait for the end event and only then invoke play on the next clip.
This can be achieved by properly handling the audio events you can look up online and "chaining" them playing one at a time, much like this:
var nextSound;
function playNext()
{
var audio;
if (nextSound >= cal.length)
{
return;
}
audio = $(window["s"+cal[nextSound++]]);
audio.on("ended", playNext);
audio[0].play();
}
nextSound = 0;
playNext();
I am trying to interact with a 3rd-party html5 video player in Chrome. I am able to obtain a valid reference to it thusly:
document.getElementsByTagName("video")[1]
...and the readyState is 4, so it's all good.
I can successfully (and with expected result) call:
document.getElementsByTagName("video")[1].play();
document.getElementsByTagName("video")[1].pause();
BUT when I call:
document.getElementsByTagName("video")[1].currentTime = 500;
...the video freezes and it doesn't advance to the new currentTime. The video duration is much longer than 500 seconds, so it should be able to advance to that spot. I have tried other times besides 500, all with same result. If I examine currentTime, it is correct as to what I just set. But it doesn't actually go there. Also I can no longer interact with the video. It ignores any calls to play() or pause() after I try to set currentTime.
Before I call currentTime, when I call play() I get this valid promise back, and everything else still works:
After I call currentTime, when I call play(), I get this broken promise back, and now nothing works on that video object:
If you have a Hulu account you can easily observe this behavior on any video by simply trying it in the Chrome developer console.
EDIT: It was pointed out to me that skipping very much ahead breaks, but skipping a short distance actually works well. Could be related to commercials interspersed.
Try below code, it will first pause then set your position then again play
document.getElementsByTagName("video")[1].pause();
document.getElementsByTagName("video")[1].currentTime = 500;
document.getElementsByTagName("video")[1].play();
Why don't you try this code.
function setTime(tValue) {
// if no video is loaded, this throws an exception
try {
if (tValue == 0) {
video.currentTime = tValue;
}
else {
video.currentTime += tValue;
}
} catch (err) {
// errMessage(err) // show exception
errMessage("Video content might not be loaded");
}
}
Pls. try this:
hv = document.getElementsByTagName("video")[1];
hv.play();
hv.addEventListener('canplay', function() {
this.currentTime = 500;
});
var myVideo=document.getElementsByTagName("video")
if(myVideo[1] != undefind)
{
myVideo[1].currentTime=500;
}
/* or provide id to each video tag and use getElementById('id') */
var myVideo=document.getElementById("videoId")
if(myVideo != undefind)
{
myVideo.currentTime=500;
}
I'm trying to measure the time between when the user clicks the play button, triggering audio.play(), and the time when the audio actually starts to play on the client. I'm just not sure which event to listen to, as per http://www.w3schools.com/tags/ref_av_dom.asp
It seems that 'play' and 'canplay' are giving me similar times, so I'm not sure of the correct one to listen to. It's rather hard for me to test since I have a fairly quick connection. I'm using the following code:
var time;
var audio = document.createElement('audio');
var uri = 'http://www.flashkit.com/imagesvr_ce/flashkit/soundfx/Creatures/Male_zombi_Zapsplat_8347/horror_monster_zombie_male_eating_body_001.mp3'
audio.setAttribute('preload', 'metadata');
audio.src = uri;
audio.addEventListener('canplay', (evt) => {
time = Date.now() - time;
alert(time);
});
audio.play();
time = Date.now()
setTimeout(function() { audio.pause(); }, 1000);
https://jsfiddle.net/67vmr476/1/
I wonder whether this is an unresolved issue or not.
OK, so I have this very simple test code:
var audio = new Audio("0.mp3");
audio.oncanplay = function() {
audio.play();
setTimeout(function() {
audio.pause();
}, 30);
}
What I intend to do is to play my sound for a very short period of time.
I know for sure that the audio (a middle-C note) starts in 0:00:00.
Note that I use the oncanplay event to make sure the audio is loaded when I try to play it.
The problem I have is that I get unpredictable results. Sometimes (most of the times, really), audio is not heard at all. Other times, audio is heard but not always for the same period of time.
I know that Javascript can be slow, but I wonder, for example in the first case, why is the timeout set at all if the audio isn't playing yet.
Is this a known issue? It is possible to have a better control over Audio?
-Thanks
Avoid using setTimeout, which is not accurate and may result (as in your case) in a race condition. Use the 'timeupdate' event to keep track of the progress. Here the song will play and auto-pause after 7 seconds:
var audio = new Audio("0.mp3");
audio.oncanplay = function() {
audio.play();
audio.addEventListener('timeupdate', function() {
console.log(audio.currentTime.toFixed());
if ( audio.currentTime >= 7 ) audio.pause();
});
}
JSFiddle Demo
What does the exception mean? How can I fix it? I am using the latest Google Chrome for Ubuntu.
INVALID_STATE_ERR: DOM Exception 11 can occur when a call to webkitEnterFullscreen is made before the video element has received its asset's metadata. The simplest solution is to defer the invocation of webkitEnterFullscreen by putting it in a callback function assigned to the video's loadedmetadata event.
In a mobile environment, you need to take things a step further by attaching that call to a touchable element so that it is user initiated since play and fullscreen actions must be driven by user interaction in mobile environments.
The code should look kind of like this:
var video, play, fullscreen;
video = document.createElement('video');
video.src = 'my_cool_video.mp4';
video.addEventListener('loadedmetadata', function () {
fullscreen.disabled = false;
}, false);
play = document.createElement('button');
play.innerHTML = 'PLAY';
play.addEventListener('click', function () {
video.play();
}, false);
fullscreen = document.createElement('button');
fullscreen.innerHTML = 'FULLSCREEN';
fullscreen.disabled = true;
fullscreen.addEventListener('click', function () {
video.webkitEnterFullscreen();
}, false);
document.body.appendChild(video);
document.body.appendChild(play);
documnet.body.appendChild(fullscreen);