I want to play sound, after my page has loaded.
Here is my JavaScript code:
var playAudio = $("#sound")[0];
playAudio.play();
Here is my HTML code:
<audio id="sound">
<source src="../music/hide.ogg" type="audio/ogg">
<source src="../music/hide.mp3" type="audio/mp3">
</audio>
Console output:
Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
I want to play sound, after my page has loaded.
Here is my JavaScript code:
var playAudio = $("#sound")[0];
playAudio.play();
Here is my HTML code:
<audio id="sound">
<source src="../music/hide.ogg" type="audio/ogg">
<source src="../music/hide.mp3" type="audio/mp3">
</audio>
Console output:
Uncaught (in promise) DOMException: play() failed because the user didn't interact with the document first.
3 Answers
Reset to default 6Most browsers block any audio that is played by a web page and is not related to user interaction (see https://developer.mozilla/en-US/docs/Web/Media/Autoplay_guide). With user interaction I mean things like pressing a button. You can't do anything against that.
But you could add a start button that displays the page and starts the music, like this:
const startbtn = document.getElementById("startbtn");
const content = document.getElementById("content");
const loader = document.getElementById("loader");
const music = document.getElementById("music");
//Add an event listner to the start button
startbtn.addEventListener("click", () => {
//Show the loader and hide the button
loader.style.display = "";
startbtn.style.display = "none";
//Wait for the music to start
music.play().then(() => {
//Hide the loader and show the content
content.style.display = "";
loader.style.display = "none";
});
});
<!-- The start button --->
<button id="startbtn">Start</button>
<!-- The actual content, hidden by default -->
<div id="content" style="display: none;">
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
<p>Bla</p>
</div>
<!-- This is displayed when the user has pressed the start button, but the music is still loading -->
<div id="loader" style="display: none;">
<p>Loading ...</p>
</div>
<!-- The music. It is started by the Javascript -->
<audio id="music" src="https://opengameart/sites/default/files/audio_preview/swing_0.mp3.ogg" style="display: none;" loop></audio>
When this happens on Google Chrome, the error is currently showing a link to this page: https://developer.chrome./blog/autoplay/.
As the post explains, Google Chrome keeps track of an individual's propensity to consume media on a site, using a metric called MEI (Media Engagement Index).
Based on that metric, an attempt to play sound on page load may or may not work. You can see a list of the scores of which Chrome keeps track by going to chrome://media-engagement/
on your browser.
To handle cases in which the play on page load doesn't work, the post suggests the following code snippet:
var promise = document.querySelector('video').play();
if (promise !== undefined) {
promise.then(_ => {
// Autoplay started!
}).catch(error => {
// Autoplay was prevented.
// Show a "Play" button so that user can start playback.
});
}
In your case it could be:
const playAudio = $("#sound")[0];
const promise = playAudio.play();
let playedOnLoad;
if (promise !== undefined) {
promise.then(_ => {
// Autoplay started!
playedOnLoad = true;
}).catch(error => {
// Autoplay was prevented.
playedOnLoad = true;
});
}
At this point you can use the playedOnLoad
value to show a button or add a listener to some other types of user interaction.
Another option (the one I'm adopting) is to always show a toggle for the sound, and to change it's state (play/stop or enable/disable) based on the result of the promise.
Please remember that the MEI score is also saved for your local development environment, so, based on your personal interaction with the page, the sound may or may not start on page load even in your local environment.
This is my code and works fine. I added two params to Notification class object
silent: false, requireInteraction: false
import silenceSound from '../assets/sounds/light.mp3';
export const playSound = async (soundPathOrBase64Data) => {
var sound;
if (soundPathOrBase64Data && soundPathOrBase64Data.toString().length) {
sound = new Audio(soundPathOrBase64Data);
} else {
sound = new Audio(silenceSound);
}
sound.load();
var promise = sound.play();
if (promise) {
//Older browsers may not return a promise, according to the MDN website
promise.catch(function (error) {
console.error(error);
});
}
};
function sendNotification(messageObj) {
if (document.hidden) {
const notification = new Notification('New message from Chat', {
icon: 'https://cdn-icons-png.flaticon./512/733/733585.png',
body: `@${messageObj?.userName || messageObj?.userEmail}: ${messageObj?.message || ''}`,
silent: false,
requireInteraction: false
});
playSound();
notification.onclick = () =>
function () {
window.open('http://localhost:5500');
};
}
}
export default function checkPageStatus(message) {
const localUser = localStorage.getItem('chat-app-user');
const parsedUser = localUser ? JSON.parse(localUser) : undefined;
if (message?.sender !== parsedUser?._id) {
if (!('Notification' in window)) {
alert('This browser does not support system notifications!');
} else if (Notification.permission === 'granted' || Notification.permission === 'default') {
sendNotification(message);
} else if (Notification.permission !== 'denied') {
Notification.requestPermission((permission) => {
if (permission === 'granted') {
sendNotification(message);
}
});
}
}
}