Reputation: 659
I have this audio tag playing in the background, and I'm able to store the progress in seconds to a cookie. But in no way I'm able to start the audio from that cookie. (for continuing on other pages)
$("p#sound audio").currentTime = $.cookie("audioTime");
<audio autoplay="autoplay" loop="loop" ontimeupdate="document.getElementById('tracktime').innerHTML = Math.floor(this.currentTime); $.cookie('audioTime', Math.floor(this.currentTime));">
<source src="audio/song.ogg" type="audio/ogg" />
<source src="audio/song.mp3" type="audio/mp3" />
Your browser does not support the audio tag.
</audio>
<span id="tracktime">0</span>
Does this have to do with the song being loaded again from start?
Thanks!
EDIT:
$("p#sound audio").get[0].currentTime
With .get[0], it doesn't work either.
Can someone please clear things up for me? Greatly appreciated!
Upvotes: 14
Views: 24368
Reputation: 1309
I had a similar problem when trying to play a HLS stream through an HTML audio element.
No matter where and how I tried to set the currentTime property on the audio element, it wouldn't work until about 2.5s after calling audioElement.play().
//Calling this
htmlElement.currentTime = 5.5;
console.log('currentTime: '+htmlElement.currentTime);
//Would return 'currentTime: 0';
What did work tho, was if I called that in a timeout with 2500-3000ms delay. After a day of debugging to pinpoint the element state in which it would allow me to set the currentTime property, so I wouldn't have to rely on a fixed timeout.
My solution was to listen to 3 HTMLMediaElement events (https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement#events): loadedmetadata, loadeddata and canplaythrough and setting custom flags when they were first reported. When all 3 were reported and the HTMLMediaElement.duration property was bigger than 0, I set the HTMLMediaElement.currentTime to my desired value inside the first HTMLMediaElement timeupdate event callback.
This can be summed up in the following code snippet:
let audioElementStates = {
'metadataloaded': false,
'dataloaded': false,
'canplaythrough': false
};
let shouldSetOldTime = true;
let audioElement = document.getById('audio-element');
audioElement.src = 'https://somedomain.com/hlsplaylist.m3u8';
audioElement.addEventListener('loadedmetadata',()=>{audioElementStates.metadataloaded = true;});
audioElement.addEventListener('loadeddata',()=>{audioElementStates.dataloaded = true;});
audioElement.addEventListener('canplaythrough',()=>{audioElementStates.canplaythrough = true;});
audioElement.addEventListener('timeupdate',()=>{
if(shouldSetOldTime &&
audioElement.duration>0 &&
audioElementStates.metadataloaded &&
audioElementStates.dataloaded &&
audioElementStates.canplaythrough){
audioElement.currentTime = 5.5;
shouldSetOldTime=false;
}
});
audioElement.play();
For reference I was using this with Vue.js in a Quasar framework mobile app packaged with Apache Cordova.
NOTE: The loadedmetadata check can probably be skipped, since loadeddata would presumably never fire before loadedmetadata.
Upvotes: 0
Reputation: 1808
This solved it for me:
$("p#sound audio").on('loadedmetadata', () => {
$("p#sound audio").get(0).load();
});
So I could later set the currentTime
without worrying about whether the audio was loaded or not.
Upvotes: 1
Reputation: 11
This works for me.
if (!isNaN(audio.duration)) {
audio.currentTime = 0;
}
Hope it helps!
Upvotes: 1
Reputation: 4900
You can set the start time by adding t=<time>
to the URL, as documented here: https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Using_HTML5_audio_and_video#Specifying_playback_range
E.g. <audio src="http://example.com/audio.mp3#t=50></audio>
Upvotes: 6
Reputation: 1838
what I found in my case is that there is an issue with context somewhere. I initialize audio under the window context but when I try to change currentTime from XMLHttpRequest response it does NOT work. I don't know the answer yet but I'm providing a clue maybe an expert in Javascript will know how to make it work.
/* initialize this.audio player */
Audio = function() {
var that = this;
// keep track of playback status
var AudioStatus = {
isPlaying : false
};
// define references to this.audio, pulldown menu, play-button, slider and time display
that.audio = document.querySelector("AUDIO");
/* load track by menu-index */
var loadTrack = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.src = '../sounds/400.mp3';
that.audio.load();
};
/* callback to play or pause */
that._play = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.play();
AudioStatus.isPlaying = true;
};
that._pause = function() {
if(that.audio == null){
log("audio null"); return;
}
that.audio.pause();
AudioStatus.isPlaying = false;
};
that.playPause = function() {
if (that.audio.paused) {
self._play();
}
else {
self._pause();
}
};
/* callback to set or update playback position */
that.updateProgress = function(value) {
if(that.audio == null){
log("audio null"); return;
}
that.audio.currentTime = value; // <<<--- it does NOT work if I call from XMLHttpRequest response but it DOES if it is called from a timer expired call back
};
that.isAudioPlaying = function(){
return AudioStatus.isPlaying;
};
};
Upvotes: 1
Reputation: 6610
At first there is an error in your code because currentTime is not a part of jQuery (but you already know this)
$("p#sound audio").currentTime // is incorrect (refers to a property of jQuery)
$("p#sound audio")[0].currentTime // is correct (refers to a property of DOM element)
I discover that the audio tag has some strange things and can be operate differently from browser to browser, for example in Chrome.
At first you have to wait for the 'durationchange
' event to be sure the length is known by the object.
After this you have to start the stream with 'play()
' (if not already started) and pause it (sometimes after a short delay) with the 'pause()
' function. Then you can change the 'currentTime' property with the value. After this you have to start the stream again by using the 'play()
' function.
Also it is sometimes needed to load the stream by yourself by using the 'load()
' function.
Something like this:
$(document).ready( function()
{
var a = $('audio:first'),
o = a[0];
a.on( 'durationchange', function(e)
{
var o = e.target;
if( o )
{
o.pause();
o.currentTime = parseInt( $.cookie("audioTime"));
o.play();
}
});
if( o )
{
o.load();
o.play();
}
});
You have to play with it to be sure what is the best in your situation, for example the resume (play again) method to delay it for a second or so.
When using this method you don't have to use the autoplay feature because most of the time it doesn't work.
Hope it helps, greetz, Erwinus
Upvotes: 3
Reputation: 1893
You need to wait until audio
source loads before you set the current time.
$(function(){
$('audio').bind('canplay', function(){
$(this)[0].currentTime = $.cookie('audioTime');
});
});
Upvotes: 10