I'm making a game made of bare JavaScript code and I want to manipulate audio in JavaScript.
Specifically, I want to let the page start playing music when some div
element is clicked and when using some function in the JavaScript code.
I know audio tag of HTML5 has a limitation that a music file associated with Audio
element cannot be played without user clicking the play button of the audio element, so I cannot do like this:
const audio = document.createElement("audio");
audio.src = "url of source";
audio.play();
//Uncaught (in promise) DOMException: play() failed because
//the user didn't interact with the document first.
//https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
Chrome's autoplay policies are simple:
Muted autoplay is always allowed. Autoplay with sound is allowed if: User has interacted with the domain (click, tap, etc.). On desktop, the user's Media Engagement Index threshold has been crossed, meaning the user has previously played video with sound. The user has added the site to their home screen on mobile or installed the PWA on desktop. Top frames can delegate autoplay permission to their iframes to allow autoplay with sound.
But I want to manage audio more freely in order to make a good UI of the game.
To achieve my goal, I think I need to introduce another library or API into the JavaScript code or still use audio tag with some tricky tips.
I'm thinking one of the choices could be Web Audio API.
Could you tell me some advice?
I tried code like the following and it worked when I clicked a div element with click event handler:
<div id="my-div">play</div>
<audio id="myAudio">
<source src="url of source" type="audio/mpeg">
</audio>
const myAudio = document.getElementById("myAudio");
const btn = document.getElementById("my-div");
btn.addEventListener("click",() => {
myAudio.play();
});
However, when I wrote like the following, it didn't work with the same error even if it didn't seem I broke the autoplay policy:
document.getElementById('my-div').addEventListener('click', () => {
const audio = new Audio('url of source');
audio.play();
});
//Uncaught (in promise) DOMException: play() failed because
//the user didn't interact with the document first.
//https://developers.google.com/web/updates/2017/09/autoplay-policy-changes
The main difference between two codes above is whether I wrote the url of the audio source file in the audio tag or wrote it in the source tag inside the audio tag. I'm guessing this makes some difference but I don't get what exactly is the problem.
You're correct. You can only be sure that the playback will not be blocked by the autoplay policy if the playback is started in response to a user gesture. A button with a click handler is the classic example but the click handler could be attached to a div as well. Let's say your div has an id called my-div
. In that case the following should work.
document.getElementById('my-div').addEventListener('click', () => {
const audio = new Audio('url of source');
audio.play();
});
Using the Web Audio API will not change the autoplay policy. Usually the same rules apply no matter which browser API is used.