We can pause all audios that have an audio tag using this code:
const sounds = document.getElementsByTagName('audio');
sounds.forEach(sound => sound.pause());
In the above code, we can select all the audio tags and do whatever we want on them.
The issue is if we create audio using new Audio there will be no audio tag on the DOM and we can't select the audio...
Here is the code I try:
setTimeout(() => play(), 3000);
function play(){
const prefixAudio = new Audio(`audio.mp3`);
prefixAudio.play();
}
How can I select this audio so that I can pause it? How can I select audios added via this method?
const prefixAudio = new Audio(`audio.mp3`);
const play = () => {
prefixAudio.play();
}
const pause = () => {
prefixAudio.pause();
}
setTimeout(() => play(), 3000);
Like this?
Related
I have a portfolio page made in WordPress and on the page I have 5 videos that need to be played when in viewport and stopped when out of viewport.
I have used the following script that works only on the first video on the page.
const video = document.querySelector("video");
let playState = null;
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
video.pause();
playState = false;
} else {
video.play();
playState = true;
}
});
}, {});
observer.observe(video);
const onVisibilityChange = () => {
if (document.hidden || !playState) {
video.pause();
} else {
video.play();
}
};
document.addEventListener("visibilitychange", onVisibilityChange);
querySelector("video");
And here is the link to the page:
http://wemedia.co.rs/portfolio-2/
So what I want to achieve is to play and pause every video when in or out of viewport.
Thank you.
You are only selecting one video to use throughout your whole js script.
You need to remember that video represents only a single video and if you want to control multiple, you need to reference them in every function that you call.
I also don't see a purpose in using playState since the way you have it, it is basically an indicator of whether the first video is on screen or not.
const videos = document.querySelectorAll("video"); // Select ALL the Videos
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
entry.target.pause(); // Pause the TARGET video
} else {
entry.target.play(); // Play the TARGET video
}
});
}, {});
for (const video of videos) observer.observe(video); // Observe EACH video
const onVisibilityChange = () => {
if (document.hidden) {
for (const video of videos) video.pause(); // Pause EACH video
} else {
for (const video of videos) video.play(); // Play EACH video
}
};
document.addEventListener("visibilitychange", onVisibilityChange);
I have the following JavaScript code that work great when I hover over a video. I like how the start and stop is broken into functions and it allows me to customize the hover play exactly how I want. However, this code only works on the first video on the page and I have several videos that are loaded on the page dynamically.
I would like to modify this code so that it will work on all videos on the page. I'm thinking that maybe the functions need to be called inside a loop? I'm not sure as I do not know JavaScript well, so any help on how to modify this code would would be much appreciated!
const video = document.querySelector("video");
function startPreview() {
video.muted = true;
video.currentTime = 5;
video.playbackRate = 2.5;
video.play();
}
function stopPreview() {
video.currentTime = 5;
video.playbackRate = 1;
video.pause();
}
let previewTimeout = null;
video.addEventListener("mouseenter", () => {
startPreview();
previewTimeout = setTimeout(stopPreview, 3000);
});
video.addEventListener("mouseleave", () => {
clearTimeout(previewTimeout);
previewTimeout = null;
stopPreview();
});
You can do event delegation to handle all videos. So:
document.body.addEventListener('mouseenter', (event) => {
if (event.target.matches('video') {
// start playing
}
});
More on the matches() method on MDN.
You would also modify the start and stop methods to take the video element as a parameter:
function startPreview(video) {
video.muted = true;
video.currentTime = 5;
video.playbackRate = 2.5;
video.play();
}
And pass them the event.target.
I tried to make a metronome using HTML and JS. I know the audio can't autoplay due to restrictions (I don't want it to anyway), so I placed an <audio ...> element with a <source ...> inside, with all (I thought?) appropriate attributes; I controlled playback using JS triggered by a button click. This works on my laptop and even in the XBox Edge browser, but on iOS browsers (both Safari and Firefox) the sound does not play. The HTML looks like this:
<button id="metronome-button">Start</button>
<audio id="metronome-audio" autoplay="0" autostart="0" loop="0">
<source src="tick.mp3" type="audio/mpeg">
</audio>
And the JS looks like this:
const metronomeAudio = document.getElementById('metronome-audio');
const metronomeButton = document.getElementById('metronome-button');
let metronomeInterval = null;
metronomeButton.addEventListener('click', () => {
metronomeInterval = setInterval(() => {
metronomeAudio.loop = false;
metronomeAudio.pause();
metronomeAudio.play();
}, 500);
});
Since this didn't work, I did more looking and found this solution in another StackOverflow thread, which uses JS and no HTML at all (other than being triggered by a button's click event):
function startMetronome () {
setInterval(() => {
let audio = new Audio('tick.mp3');
audio.loop = false;
audio.play();
audio.onended = () => {
audio.remove();
}
}, 500);
}
Again, this works on PC in various browsers, why does this fail specifically on iOS? (Have not tested on Android, don't have device.)
I am not sure if this is documented anywhere (I didn't stumble across it), but after some additional testing I discovered that iOS prohibits use of the .play() function on an existing HTML <audio> element or JS Audio() element, unless called directly and synchronously as the result of a user UI event. In other words, this will work:
const button = document.getElementById('my-button')
const audio = document.getElementById('my-audio')
button.addEventListener('click', () => {
audio.play()
})
But this will not work:
const button = document.getElementById('my-button')
const audio = document.getElementById('my-audio')
button.addEventListener('click', () => {
setTimeout(() => { audio.play() }, 1000)
})
Thus, having the .play() call in an async callback breaks playback on iOS.
However, as mentioned in a comment on this answer here: https://stackoverflow.com/a/54432573/983173, if you instantiate your audio element within a synchronous user interaction event handler, you can re-use and re-play (e.g. .play()) an Audio() element as much as you like. For example:
const button = document.getElementById('my-button')
let audio = null
button.addEventListener('click', () => {
audio = new Audio('myAudio.mp3')
// Works because `audio` itself was created synchronously during user event handler
setTimeout(() => { audio.play() }, 1000)
})
I have an <audio> object that might need to load before it can play, is there a way to trigger a function when either the sound begins after downloading, or when the user clicks the play button?
There is a playing event you can listen to like so.
audio.addEventListener("playing", function() {
console.log("playing");
});
http://w3c.github.io/html/semantics-embedded-content.html#eventdef-media-playing
Yes, there is onplay event for audio and video, you should use <audio> tag to do it
var audio = document.getElementById("Your_audio");
audio.onplay = function() {
//your code
};
with the javascript audio object you can add some event listener, like :
var horn = new Audio('car_horn.wav');
horn.addEventListener('loadeddata', () => {
let duration = horn.duration;
// The duration variable now holds the duration (in seconds) of the audio clip
})
as you can see here : https://developer.mozilla.org/en-US/docs/Web/API/HTMLAudioElement
you can simply add an evenListner like this:
<audio|video onplay="myScript">
e.g. you can do like this:
var aud = document.getElementById("myAudio");
aud.onplay = function() {
alert("The audio has started to play");
};
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.