HTML 5 Audio Detecting Play Delay - javascript

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/

Related

How to autoplay audio when the countdown timer is finished?

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>

AudioContext .ended not firing properly

I have a simple routine that creates an audiocontext node and loads it with a buffer. The onended event seems to fire at the start. I set a timer for the duration and the onended event triggers about that amount of time before the audio stops playing. Anybody know how to get a true onended event. I tried to use the destination as well as the source, same result
function playSoundFile(buffer) {
'use strict';
audioCtx.close();
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
audioSource = audioCtx.createBufferSource();
audioSource.connect(audioCtx.destination);
audioSource.buffer = buffer;
audioSource.playbackRate.value = 1;
stillPlaying(true);
audio_player = audioCtx.destination;
audioSource.addEventListener('onended', whatsUp());
console.log('start ' + showTime());
filePlayed(buffer.duration);
audioSource.start();
}
the timestamp is only 1 ms different between the play and the onended event.
filePlayed starts a timeout event to show time at beginning and end.
Okay, guest271314 had it mostly right.
the documentation is confusing. The eventListener is "ended" not "onended" and you have to use function name with the parans
so
audioSource.addEventListener('ended', whatsup);
takes care of the problem. Thanks.

How to pause/stop video in actually time (like 3.00 secs)

I was wondering is there possible to pause the video in actually time ?
I tested and video always pause at x.xxx not x.00
video.load();
video.play();
video.ontimeupdate = function(){
if(this.currentTime >= 3) {
video.pause();
}
};
Demo : https://jsfiddle.net/l2aelba/4gh7a058/
Any trick ?
PS: Should be good performance as possible also
I believe you cannot guarantee that the video will stop at an exact moment in time.
According to the documentation for media controller:
Every 15 to 250ms, or whenever the MediaController’s media controller
position changes, whichever happens least often, the user agent must
queue a task to fire a simple event named timeupdate at the
MediaController.
timeupdate event will fire when it can using the least often scenario. It does not give you the option to choose the exact fire times for the updates.
A trick you could do is the following: Remove the timeupdate event, set your own interval and using that check the time.
setInterval(function () {
var ct = video.currentTime;
current_time_el.innerHTML = 'Current time : ' + ct;
if(ct >= 3) {
video.pause();
}
}, 40);
This approach will force you to be more careful with your code though. (e.g clean up your interval with clearInterval() when it is not needed any more)

Can't avoid delay in javascript audio

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

HTML5 AudioPlayer Event Action 'Ended' is being call more than One time

I am working with HTML5 Audio Player. I am implementing playlist. I am using 'ended' event action to play the next audio media file. But, At the end of media file, 'ended' event is fired more than one time. (As the message I log appears more then one time.)
This is my Event Listener:
//Event Listener
function addPlayerListener() {
console.log("Recording Index: "+combinedSessionIndex);
var audio = document.getElementById("playarea");
audio.addEventListener('ended', function () {
sessionsToPlay = $("#audio_files").val().split(',');
console.log ("In Recording End Event Listener...!!!"+combinedSessionIndex);
//It Shows Length '1' not '0'
if (sessionsToPlay.length == 1) {
console.log("Returned Due to Session To Play length..!!!")
return;
}
//As CombinedSessionIndex Starts with 1
if (combinedSessionIndex == sessionsToPlay.length) {
console.log("Returned Due to All Session To Play Got Finish..!!!")
$("#audio_files").val("");
sessionsToPlay = [];
combinedSessionIndex = 0;
return;
}
var filePath = '${properties["RECORDED_SESSION_RETREIVAL_PATH"]}';
filePath = filePath + sessionsToPlay[combinedSessionIndex] + ".mp4";
combinedSessionIndex++;
audio.src = filePath;
audio.play();
}, false);
}
So, When a particular media file ends, it skips next media files and start playing next (after skipping 1,2) file. For each skipped media file, control comes in event listener, which shows that event listener is being call repeatedly while single call ends.
For the first Time I play audio file by this code:
//PlayBack Session
function play(data) {
//Just to deal with a scenario that when we play a combined session and in the mean while we start listening any other single
//session, then after completion of this single session, remaining previous combined session should not resume.
//console.log("Re-setting Player ...!!!");
//$("#audio_files").val("");
//sessionsToPlay = [];
//combinedSessionIndex = 0;
var filePath = '${properties["RECORDED_SESSION_RETREIVAL_PATH"]}';
filePath = filePath + data + ".mp4";
console.log("filePath: " + filePath);
if (data == null || data == "") {
alert("Nothing to Play ...!!!");
return;
}
$("#playarea").attr({
"src": filePath,
"autoplay": "autoplay"
})
}
And after that when this ends, further clips are played using 'ended' event listener.
I am unable to find reason for this. Please guide me if I am doing anything wrong ?
Thanks in Advance :)
Ahh My bad. I was registering the same Event Listener 'Ended' frequently (Each time user presses Play Button, while it should be just single time). That's why I was getting 'ended' events more than one time. It actually generates the 'Ended' event action for the number of times I register for 'Ended' event.
Do you not think it should consider just once ? Because our purpose is just getting notified when media file gets end. There's no logic of notifying multiple times though we register for multiple times.

Categories