Using jQuery + Javascript play HTML5 Audio elements with spacing - javascript

var audioPlaying = false;
if (!audioPlaying) {
// get a random audio element that has the class .sound
audio = $('.s' + (Math.round(Math.random() * $('.sounds').size())));
audio.get(0).play();
audioPlaying = true;
setTimeout(function(audioPlaying) {
audioPlaying = false;
}, 1000);
}
I'm working on a javascript thing that plays a sound on an event. I need to not play more than one sound every second. I have a function checks if audio is playing (via a true/false variable), then, if so, selects a random audio element and plays it. It then sets the variable to say audio is playing (true), then sets a timeout to switch the variable back to false after 1 second.
This should make it so that audio is played after at a minimum of 1 second. However, it doesn't seem to ever set the audioPlaying variable back to false. One of the sounds is played and none after that. If I remove the code that changes audioPlaying to true, the sounds are played without any spacing between them.
Anyone know what's wrong?

Try something like this:
var audioPlaying = {
_audioPlayingNow: false,
playAudio: function()
{
if ( !audioPlaying._audioPlayingNow )
{
var audio = $('.s' + (Math.round(Math.random() * $('.sounds').size())));
audio.get(0).play();
audioPlaying._audioPlayingNow = true;
setTimeout( audioPlaying._resetAudioPlaying, 1000 );
}
else
{
setTimeout( audioPlaying.playAudio, 1000 );
}
},
_resetAudioPlaying: function()
{
audioPlaying._audioPlayingNow = false;
}
}

Related

Don't Work JS Audio Random Sounds

I'm create audio button. The sound will start when we click on the button and we will click again stop it. I want random uninterrupted sound when we press the button. I created a sample JS, but when the sound ends, the sound does not change automatically.
I recently tried the code below. When I use this code, the button is starting to sound(okey), the sound is changing(okey), but when we pause click, the sound is not stopping. The sound changes, the sound changes again when we click again. What kind of method should I try?
var sounds = new Array();
sounds[0]="http://static1.grsites.com/archive/sounds/background/background001.mp3";
sounds[1]="http://static1.grsites.com/archive/sounds/background/background002.mp3";
sounds[2]="http://static1.grsites.com/archive/sounds/background/background003.mp3";
sounds[3]="http://static1.grsites.com/archive/sounds/background/background004.mp3";
sounds[4]="http://static1.grsites.com/archive/sounds/background/background005.mp3";
document.getElementById("playpause").addEventListener("click", function getRandomSounds(){
var audio = document.getElementById('testAudio');
var randomNum = Math.floor(Math.random() * sounds.length);
document.getElementById("testAudio").src = sounds[randomNum];
if(this.className == 'is-playing'){
this.className = "";
this.innerHTML = "Pause"
audio.pause();
}else{
this.className = "is-playing";
this.innerHTML = "Play";
audio.play();
}
document.getElementById("testAudio").addEventListener("ended", getRandomSounds);
getRandomSounds();
});
<html>
<body>
<input type="checkbox" value="None" id="playpause" name="check" />
<label for="playpause" tabindex=1></label>
<audio id="testAudio"></audio>
</body>
</html>
try removing the following this code:
document.getElementById("testAudio").addEventListener("ended",
getRandomSounds);
It looks like there were a few logical problems with the solution you had. The biggest ones were confusion with referencing elements for checkbox vs. label (so I simplified to a button), and that you were using the same event for play/pause as you were for queing the next item. So, as soon as it would try to queue one, it would also pause.
<html>
<body>
<input type="button" value="Play" id="playpause">
<audio id="testAudio"></audio>
</body>
</html>
var sounds = new Array();
sounds[0] = "http://static1.grsites.com/archive/sounds/background/background001.mp3";
sounds[1] = "http://static1.grsites.com/archive/sounds/background/background002.mp3";
sounds[2] = "http://static1.grsites.com/archive/sounds/background/background003.mp3";
sounds[3] = "http://static1.grsites.com/archive/sounds/background/background004.mp3";
sounds[4] = "http://static1.grsites.com/archive/sounds/background/background005.mp3";
document.getElementById("playpause").addEventListener("click", function() {
var audio = document.getElementById('testAudio');
var doPlay = this.className != 'is-playing' && audio.src != null;
if (audio.src == null) {
getRandomSound();
}
if (this.className == 'is-playing') {
this.className = "";
this.value = "Play"
audio.pause();
} else if(doPlay) {
this.className = "is-playing";
this.value = "Pause"
audio.play();
}
document.getElementById("testAudio").addEventListener("ended", getRandomSounds);
});
function getRandomSound() {
var audio = document.getElementById('testAudio');
var randomNum = Math.floor(Math.random() * sounds.length);
document.getElementById("testAudio").src = sounds[randomNum];
audio.play();
};
I also updated it here so that the pause is just a pause and won't change the selected track until the one you're on has ended. I'm not sure if that's the intended or not, but by the description, I'm guessing that's what you'd want. Otherwise, it's a simple edit to go to a new track on every new start.
I've done a reasonable amount with playing sound from the browser, and the best option I found was to use a soundmanager js. I used SoundManager2 from here: http://www.schillmania.com/projects/soundmanager2/demo/template/ I'm sure there are others that would work though. The problem is that different browsers have different capabilities and expectations, so in order to get a best-case working scenario, you need something that uses html5 with flash as a backup option. I can verify that the one I linked works in Edge, Firefox, and Chrome (desktop and mobile), but I can't verify any other browsers for certain. I've been using it for audio responses in a warehouse application, so I can also verify that it's reliable when implemented correctly, but I haven't used play/pause on it or the interface. I just play from the background.
here's my setup as an implementation example if you end up working with that one:
var soundReady = false;
var QueuedSounds = [];
soundManager.setup({
url: '/Scripts/SoundManager/',
// flashVersion: 9, // optional: shiny features (default = 8)
preferFlash: false,
onready: function () {
// Ready to use; soundManager.createSound() etc. can now be called.
soundReady = true;
QueuedSounds.Each(function (s) {
var mysound = soundManager.createSound({
id: 'mySound',
url: s.filename,
autoLoad: true,
autoPlay: true,
onfinish: function () {
this.destruct();
},
volume: 100
});
});
}
});
function PlaySound(filename, mime) {
if (soundObject != null) {
$(soundObject).remove();
soundObject.removed = true;
soundObject = null;
}
if (soundReady) {
var mysound = soundManager.createSound({
id: 'mySound',
url: filename,
autoLoad: true,
autoPlay: true,
onfinish: function () {
this.destruct();
},
volume: 100
});
}
else {
QueuedSounds.push({ filename: filename, mime: mime });
}
}

A-Frame - playing / pausing sound with a custom ('a-sound') source

Edit 2: Here is the working code. Many thanks to Piotr for his help I couldn't have done it so effortlessly without you guys.
sceneEl.querySelector('a-sound').setAttribute('sound', {src:url3});
let playing = false;
var el = document.querySelector('a-box');
let audioEl = document.querySelector("a-sound");
var audio = audioEl.components.sound;
el.addEventListener('click', () => {
if (!playing) {
audio.playSound();
} else {
audio.stopSound();
}
playing = !playing;
})
} );
request.send( null );
}
});
Edit: I've got the sound playing from a dynamic URL (in my JSON file), but I cant seem to get the event listener function right (for playing / pausing on click).
sceneEl.querySelector('a-sound').setAttribute('sound', {src:url3});
let audioEl = document.querySelector("a-sound");
let audio = audioEl.components.sound;
sceneEl.querySelector('a-box').addEventListener('click', function () {
if(!playing) {
audio.play();
} else {
audio.pause();
audio.currentTime = 0;
}
playing = !playing;
});
} );
request.send( null );
}
});
Original: I'm using this component in A-Frame, but I'm looking to play the sound from the src in the ('a-sound') entity rather than from the asset link. The reason is because I'm loading the sound files dynamically from a JSON array so they don't exist in any list of assets. I've got all my files loading but am having trouble getting this component to hook into my loaded sceneEl.querySelector('a-sound').setAttribute('sound', {src:url3}); code. I'm thinking its just a small syntax issue but I'm not 100% sure. Could someone please look over this for a minute and tell me if its doable? This is the code (same as the link except for the (a-sound) within the querySelector.
AFRAME.registerComponent('audiohandler', {
init:function() {
let playing = false;
let audio = document.querySelector('a-sound');
this.el.addEventListener('click', () => {
if(!playing) {
audio.play();
} else {
audio.pause();
audio.currentTime = 0;
}
playing = !playing;
});
}
})
</script>
Using the <a-sound> You must handle things a bit differently.
playing / stopping the sound should be done within the sound component. You need to access it via yourEntityName.components.sound and use the playSound() and stopSound() methods.
check it out on my glitch. I set the source via the setAttribute(), and make a play / stop button.
My <a-sound> has a geometry to be a button, but You can make a <a-sound> entity, and use it like this:
let audioEl = document.querySelector("a-sound");
audioEl.setAttribute("src", "sourceURL");
let audio = audioEl.components.sound;
// play = audio.playSound();
// stop = audio.stopSound():
Furthermore, there are many issues with the nodes not being fully loaded. Check out this example:
<a-entity component></a-entity>
<a-sound></a-sound>
If the component tries to grab a reference to the document.querySelector("a-sound").components.sound, it may be undefined. If so, You should try to wait until it emits the loaded signal.

Javascript - how to tell the video element to stop playing the video at xyz duration?

I have content in French, Nederland, English (on same topic example: "global warming" )
But its in one large file, how can i tell the video element to please play from duration 00:00:00 till 00:05:00 only do not play the whole 02:00:00 ?
function video_play_onetime_withcut(input) {
$('#mediaplayer').prop('loop', false);
$('#mediaplayer').attr('src', filename).show();
mediaplay_video= document.getElementById('mediaplayer');
mediaplay_video.play();
mediaplay_video.onended = function(e) {
console.log('>>> Playing finished: ', e);
};
}
Use timeupdate event.
mediaplay_video.ontimeupdate = function(event) {
if( mediaplay_video.currentTime === 5 * 60 ) {
mediaplay_video.pause();
// Just so we don't stop the player multiple times if the user
// wants to see the whole thing...
mediaplay_video.ontimeupdate = false;
// Do whatever you want.
}
};
If you plan to hide the player afterwards, you can use this:
mediaplay_video.ontimeupdate = function(event) {
if( mediaplay_video.currentTime >= 5 * 60 ) {
mediaplay_video.pause();
// #TODO: Remove player element...
}
};
More information can be found here.
You should be able to use a timeout function.
var clipLength = 10000; //milliseconds
window.setTimeout(function(){
mediaplay_video.stop();
}, clipLength);

Stopping/Pausing audio when another audio file is clicking using jQuery

I have created a site with image thumbnails of people I have photographed. When a visitor clicks on one of the thumbnails the full image is revealed using jQuery, and an audio introduction plays. I have a different audio introduction for each thumbnail/image combination - 15 at present with more being added daily.
I would like to ensure that if a visitor clicks on another thumbnail before the previous audio file has completed, that the previous audio file is stopped/paused to allow the new audio file to be played - thereby ensuring two or more tracks do not play simultaneously.
I am currently using the following snippet of code, wrapped in an anonymous function, to play each audio file individually when the appropriate thumbnail is clicked - so this snippet is duplicated for each audio file, but don't know how to ensure they do not play over one another.
$(".bridget-strevens").click(function(){
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused){
audio.play();
} else {
audio.pause();
}
});
Any help you could give me would be very grateful, as I am just starting to learn jQuery, and don't have the knowledge to come up with a workable solution.
Thanks in advance for your help!
Add a .audio class to all your audio elements and loop through all of them when an audio is clicked.
$(".bridget-strevens").click(function () {
$('.audio').each(function (index, value) {
if (!value.paused) {
value.pause();
}
});
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
} else {
audio.pause();
}
});
If that seems too heavy for you then simply add the audio element in a global variable such as:
var currentAudio;
Then when a new audio is clicked, simply pause that one, play the new one and update the currentAudio variable with the new element currently being played.
var currentAudio = null;
$(".bridget-strevens").click(function () {
if(currentAudio != null && !currentAudio.paused){
currentAudio.pause();
}
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
currentAudio = audio;
} else {
audio.pause();
}
});
Update:
Thanks for the prompt responses! Grimbode, I've tried what you
suggest, and that seems to work. However is there the ability to stop
and reset rather than just pause - so if they clicked on 1 then [2]
before 1 finished, then clicked 1 again, that 1 would start from
the beginning again rather than the point at which it was paused? And
is there any way of check the state 'globally', and then add code for
each individual audio file - just to keep the amount of code and
duplication down? Thanks again!! –
Yes. Play audio and restart it onclick explains in detail how to do this. The final result would look something like this:
var currentAudio = null;
$(".bridget-strevens").click(function () {
if(currentAudio != null && !currentAudio.paused && currentAudio != this){
currentAudio.pause();
//Here we reset the audio and put it back to 0.
currentAudio.currentTime = 0;
}
var audio = $('#bridget-strevens-intro')[0];
if (audio.paused) {
audio.play();
currentAudio = audio;
} else {
audio.pause();
}
});
You can't really optimize the code much more. You're going to have apply the click event on every audio element. You're going to have to keep the current playing audio element memorized so you don't have to loop through all the audio files.
If you really want to take this further you could create a library to handle everything. Here is an example:
(function(){
var _ = function(o){
if(!(this instanceof _)){
return new _(o);
}
if(typeof o === 'undefined'){
o = {};
}
//here you set attributes
this.targets = o.targets || {};
this.current = o.current || null;
};
//create fn shortcut
_.fn = _.prototype = {
init: function(){}
}
//Here you create your methods
_.fn.load = function(){
//here you load all the files in your this.targets.. meaning you load the source
//OR you add the click events on them.
//returning this for chainability
return this
};
//exporting
window._ = _;
})();
//here is how you use it
_({
targets: $('.audio')
}).load();

Setting the currentTime of an <audio> tag not working?

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!
You need to wait until audio source loads before you set the current time.
$(function(){
$('audio').bind('canplay', function(){
$(this)[0].currentTime = $.cookie('audioTime');
});
});
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>
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
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;
};
};
This works for me.
if (!isNaN(audio.duration)) {
audio.currentTime = 0;
}
Hope it helps!
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.
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.

Categories

Resources