I have an HTML5 game that uses audio notifications.
When users are searching for other players with match-making they frequently change tabs to do other things and rely on the audio notification to know when to come back. This no longer works after Chrome (desktop) changed to disallow audio notifications.
How can I ensure the audio notifications still work in the background?
I have an HTML5 game that uses audio notifications.
When users are searching for other players with match-making they frequently change tabs to do other things and rely on the audio notification to know when to come back. This no longer works after Chrome (desktop) changed to disallow audio notifications.
How can I ensure the audio notifications still work in the background?
Share Improve this question edited Mar 28, 2016 at 19:20 Tim Penner 3,54122 silver badges36 bronze badges asked Feb 20, 2016 at 16:36 HarryHarry 54.9k76 gold badges185 silver badges270 bronze badges 7- I have Chrome 49.0.2623.75 m, from 2016-03-03, and this works for me in background tab with setTimeout. – Serge Seredenko Commented Mar 17, 2016 at 22:09
- Refer to this: stackoverflow.com/questions/14917531/… – Koustav Ray Commented Mar 21, 2016 at 10:46
- There are two concepts here and I need to understand which ones do you need: there is first the Notification API, which allows websites to send you notifications even if they are not opened and they have sound options, and then there is the concept of a background tab making a sound. Which ones do you need? – Siderite Zackwehdex Commented Mar 23, 2016 at 13:02
- @SideriteZackwehdex it's the latter one. – Harry Commented Mar 23, 2016 at 14:13
- Are you working with Desktop or Android... My assumption has been desktop because there is no Android tag or mention of Android. – Tim Penner Commented Mar 23, 2016 at 20:09
3 Answers
Reset to default 8The solution that worked for me was to play a small blank sound (0.1 second is enough) once the page is loaded. After that even if you switch to another tab, the tab in the background will still be able to play the sound on some external or internal event.
Example 1
Here is an example that creates a div and uses HTML5 <audio>
tag with a fallback to <embed>
that plays an audio file 3 seconds after clicking the button.
To test it, run the sample and click the button, then change tabs and count 3 seconds. You should see the speaker icon on this tab and hear the coin drop sound after 3 seconds even though this tab is not the current tab.
function playCoinDrop() {
soundDiv = document.createElement("div");
soundDiv.innerHTML = '<audio autoplay="autoplay"><source src="http://themushroomkingdom.net/sounds/wav/smw/smw_coin.wav" type="audio/wav" /><embed hidden="true" autostart="true" loop="false" src="http://themushroomkingdom.net/sounds/wav/smw/smw_coin.wav" /></audio>';
}
<button onclick="setTimeout(playCoinDrop, 3000)">play sound</button>
You can replace the audio file as you see fit.
Example 2 - localStorage
Here is a more advanced way that utilizes localStorage
which will probably be your best option. This allows you to preload the notification sound by downloading it into localStorage as Base64 and then you can invoke playing it when the tab is in the background without causing additional network transfers.
A major benefit to this approach is that there is only one download of the notification file, and then after that it is played locally from the browsers localStorage.
downloadCoin()
function stores the file in localStoarge
as base64
playCoinDrop()
creates a div on the fly and plays the base64 data
playCoinDropJS()
plays the base64 data without creating any div
function downloadCoin() {
var coin = 'smw_coin.wav';
var xhr = new XMLHttpRequest();
xhr.open('GET', coin, true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = new Blob([this.response], {
type: 'audio/wav'
});
var reader = new window.FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function() {
var coinB64 = reader.result;
var myStorage = localStorage.setItem('coin_base64', coinB64)
}
}
};
xhr.send();
}
function playCoinDrop() {
var coinB64 = localStorage.getItem('coin_base64');
var soundDiv = document.createElement('div');
soundDiv.innerHTML = '<audio autoplay="autoplay"><source src="' + coinB64 + '" type="audio/wav" />';
}
function playCoinDropJS(){
var coinB64 = localStorage.getItem("coin_base64");
var snd = new Audio(coinB64);
snd.play();
}
<button onclick="downloadCoin()">download</button>
<button onclick="setTimeout(playCoinDrop, 3000)">play sound</button>
<button onclick="setTimeout(playCoinDropJS, 3000)">play sound JS</button>
demo on github
Here, background tabs still can play sounds from <audio>
elements (Chrome 49.0.2623.87). However, if Chrome blocked this, a way to work around it would be to notify the front tab of an event and have it play the sound instead of the background tab.
The following would need to be implemented as a userscript extension so that it could work on any tab - as a demo, it works just between two tabs with the same JSBin URL:
var intercom = Intercom.getInstance();
document.addEventListener("visibilitychange", getVisible);
function getVisible (evt) {
document.getElementById("fg-indicate").style.visibility = document.visibilityState;
if (document.visibilityState == "visible") {
// tab comes to front => listen to intercom
intercom.on('notice', play);
} else {
// kill callback
intercom.off('notice', play);
// call intercom with delay
window.setTimeout(function f() {
intercom.emit('notice', {message: 'Hello, all windows!'});
}, 3000);
}
}
function play() {
document.getElementsByTagName("audio")[0].play();
}
It relies on the intercom.js library and uses localstorage to communicate between open tabs.
Try this out by
- opening https://jsbin.com/gerihijofe/1/edit?html,js,output in one tab
- then in another tab
- switch tabs
- wait for 3s, see where the little speaker icon appears
- switch tabs
- wait for 3s, see where the little speaker icon appears
and so on.
The code and a bit more code to inject an <audio>
element could be wrapped in a userscript so it can run on any site that happens to be in front.