39

I'm trying to get a small sound file to play automatically using an tag and javascript to initiate it.

<audio id="denied" preload="auto" controls="false">
    <source src="sound/denied.wav" />
 </audio>

And then through javascript, at the appropriate time:

$('#denied')[0].play()

Works fine on Chrome on my desktop. In Android 4.1.1, the sound will not play, unless I hit "play" on the HTML5 audio controls before javascript attempts to play it.

So basically the Android browser (stock or Dolphin) will not play the audio unless the user initiates it at some point before the javascript. Is this intended? Is there any way around this?

Jonah H.
  • 1,760
  • 4
  • 18
  • 31

9 Answers9

19

Well, for my purposes, here's what I did:

Luckily, before the user can trigger the behavior to start audio, they have to click a button. I set the volume of the element to 0.0, and have it "play" when they click this button.

After the sound is played silently, I simply set the volume property back to 1.0, and it plays without user intervention just fine.

Jonah H.
  • 1,760
  • 4
  • 18
  • 31
13

In my case this was an easy solution:
https://stackoverflow.com/a/28011906/4622767
Copy & paste this in your chrome:

chrome://flags/#autoplay-policy

My web app has many page reload so I can't force the user to press a button every time; but it is for internal usage, so I can force the users to use chrome and configure that option.

Wilfred Springer
  • 10,869
  • 4
  • 55
  • 69
FRa
  • 354
  • 4
  • 8
  • 2
    Caution: this option has a new name: Autoplay policy. – Arnaud Feb 26 '18 at 21:39
  • 4
    This solves it for me, what about everyone visiting my site? – Munim Munna Apr 03 '18 at 09:35
  • is not there on ipads – AndiDev Oct 10 '18 at 22:04
  • 2
    For the newer version of chrome i had to do the following `Settings -> Privacy and Security -> (Additional content settings) Sound => Add site/file to Allow list` This is useful if you need to have something working locally. These solutions are not for visitors to your site. – Chad Cache Jan 11 '21 at 13:19
10

I know that in mobile safari any javascript call to play() must be in the same call stack as a user initialted click event. Spoofing the the click with a javascript trigger won't work either.

On my nexus 7 I can confirm that unless the javascript was triggered by a user click, it does not play.

Rob Lynch
  • 591
  • 4
  • 11
  • In mobile Safari, you can trick Safari by having the user click a button and play a short silent sound. No volume tricks or anything required, that seems to do the trick there. Not sure if that will work on Android though. – toon81 Sep 11 '13 at 11:51
10

The main issue is that sound (on iOS and Android) must be triggered by a user click. My workaround was very simple. Tie the audio.play() to a click event listener and then immediately pause it. From that point and on the sound works perfect.

var myAudio = new Audio('assets/myAudio.mp3');
...
button.addEventListener("click", function() {
    myAudio.play();
    myAudio.pause();
    ...
});
Neuron
  • 5,141
  • 5
  • 38
  • 59
Eli Mashiah
  • 200
  • 2
  • 5
  • 9
    myAudio.play() returns a promise! This code will result into an exception: Use the then method. For Example: `myAudio.play().then(() => {myAudio.pause()})` – maracuja-juice Nov 08 '17 at 07:51
  • I've tried this solution but I'm still getting an error (in Promise) in Chrome about the user not interacting first. Have the browsers updated so this won't work now or am I missing something @maracuja-juice? Vars: `var trigger = document.getElementById("trigger"); var audio = new Audio('media/hello.mp3');` Play/Pause: `trigger.addEventListener("click", function() {audio.play().then(() => {audio.pause()}) });` Original intention of hover: `trigger.addEventListener("mouseover", function( event ) { audio.play(); }, false);` – user1406440 Jul 17 '22 at 16:15
4

Here is a blog-post on the reason and how to overcome it by loading all the audio files on first user interaction and play them later in programmed manner: https://blog.foolip.org/2014/02/10/media-playback-restrictions-in-blink/ Adopting this approach a small javascript module is available on GitHub https://github.com/MauriceButler/simple-audio

I tried this simple approach on my own - worked seamlessly & great!

makechaos
  • 41
  • 1
3

Luckily for me the html5 app I'm working on only needs to work in Android 4.1, but if you're trying to make something cross-platform you'll need to adapt this slightly. Neither setting volume to 0.0 then back or autoplay on the control worked for me. I also tried muted and that didn't work either. Then I thought, what if I set the duration and only play a miniscule amount of the file? Here's yet another hacked-together script that actually did work:

function myAjaxFunction() {
  clearTimeout(rstTimer); //timer that resets the page to defaults
  var snd=document.getElementById('snd');
  snd.currentTime=snd.duration-.01; //set seek position of audio near end
  snd.play(); //play the last bit of the audio file
  snd.load(); //reload file
  document.getElementById('myDisplay').innerHTML=defaultDisplay;
  var AJAX=new XMLHttpRequest(); //won't work in old versions of IE
  sendValue=document.getElementById('myInput').value;
  AJAX.open('GET', encodeURI('action.php?val='+sendValue+'&fn=find'), true);
  AJAX.send();
  AJAX.onreadystatechange=function() {
    if (AJAX.readyState==4 && AJAX.status==200) {
      document.getElementById('myDisplay').innerHTML=AJAX.responseText;
      if (document.getElementById('err')) { //php returns <div id="err"> if fail
        rstTimer = setTimeout('reset()', 5000); //due to error reset page in 5 seconds
        snd.play(); //play error sound
        document.getElementById('myInput').value=''; //clear the input
      }
    }
  }
}
MaKR
  • 1,882
  • 2
  • 17
  • 29
3

You don't need JavaScript for autoplay, and I see several issues in your code:

<audio id="denied" preload="auto" controls="false">
    <source src="sound/denied.wav" />
</audio>

I'd change it to (in HTML5 you don't need attribute="value" syntax in some cases, that's for XHTML):

<audio id="denied" autobuffer controls autoplay>
    <source src="sound/denied.wav" />
</audio>
<a href="#" id="play-button">play!</a>

In iOS autoplay is disabled, you need to click play button or put a user click event on custom controls like this with JavaScript:

var audio = document.getElementById('denied');
var button = document.getElementById('play-button');
button.addEventListener('click',function(){
    audio.play();
});

or with jQuery:

$('#play-button').click(function(){ audio.play(); });}

Edit

Keep in mind that HTML5 is pretty recent technology (at least some functionalities), so browser compatibility and functionality changes every once in a while.

I encourage everybody to keep informed about the current status, as sometimes things start to be less hack-dependant, or the other way around.

A good starting point: http://caniuse.com/#feat=audio (check the tabs at the bottom).

Also for a global audio solution I recommend using SoundManager2 JS library

aesede
  • 5,541
  • 2
  • 35
  • 33
2

It happened to me too. Here's how I hacked this:

I set the audio to autoplay and set the vol to 0. When I need it to play, I use the load() method and it will autoplay. It's a light mp3 file and it plays every one hour/two hour, so this works fine for me.

Xpleria
  • 5,472
  • 5
  • 52
  • 66
Marks
  • 327
  • 3
  • 14
2

I met the same problem in my app. My application usage scenario was like this:

  1. click the button to show a table with information (user action)
  2. show the table and refresh data in it by AJAX
  3. play sound when data has been changed

Fortunately I had the user action (step 1) so I was able to "initiate" the sound by it and then play it by javascript without the user action needed. See the code.

HTML

<audio id="kohoutAudio">
    <source src="views/images/kohout.mp3">
</audio>

<button id="btnShow">Show table</button>

Javascript

$("#btnShow").click(function () {
    //some code to show the table
    //initialize the sound
    document.getElementById('kohoutAudio').play();
    document.getElementById('kohoutAudio').pause();
});

function announceChange(){
    document.getElementById('kohoutAudio').play();
};
Pawel
  • 16,093
  • 5
  • 70
  • 73
Luboš Miřatský
  • 1,459
  • 1
  • 12
  • 15