Howler.js: Failed to execute 'play' on 'HTMLMediaElement': API can only be initiated by a user gesture.

Created on 30 Aug 2016  路  18Comments  路  Source: goldfire/howler.js

I am getting this error on Android and Iphone. I am calling play based on a button click, but still get this error thrown. Any suggestions?

Most helpful comment

@goldfire I've been having this problem with various Android browsers and iOS.

The issue is that mobile devices require a gesture to be the origin for calling the play() method on a HTMLMediaElement. Howler currently wraps the triggering of play() in an anonymous function, which essentially "strips" a gesture induced JS event from its origin.

This commit introduces wrapping play() in an anonymous function: https://github.com/goldfire/howler.js/commit/18a91c5f

At one point in time, Firefox (probably version 13) had an issue solved by wrapping the node.play() in a zero-second timeout. Now, it's preventing a wide array of Android browsers and iOS of using Howler with HTML5 Audio because of this restriction in the mobile browsers.

I've tested and confirmed that removing the setTimeout() (https://github.com/goldfire/howler.js/blob/master/src/howler.core.js#L739) solves the problem on a number of phones from LG, Huawei, Nexus, HTC, and Samsung (and various iOS devices).

Can we take it out?

I will be forced to patch howler with this fix for my own use until it's resolved.

All 18 comments

@goldfire I've been having this problem with various Android browsers and iOS.

The issue is that mobile devices require a gesture to be the origin for calling the play() method on a HTMLMediaElement. Howler currently wraps the triggering of play() in an anonymous function, which essentially "strips" a gesture induced JS event from its origin.

This commit introduces wrapping play() in an anonymous function: https://github.com/goldfire/howler.js/commit/18a91c5f

At one point in time, Firefox (probably version 13) had an issue solved by wrapping the node.play() in a zero-second timeout. Now, it's preventing a wide array of Android browsers and iOS of using Howler with HTML5 Audio because of this restriction in the mobile browsers.

I've tested and confirmed that removing the setTimeout() (https://github.com/goldfire/howler.js/blob/master/src/howler.core.js#L739) solves the problem on a number of phones from LG, Huawei, Nexus, HTC, and Samsung (and various iOS devices).

Can we take it out?

I will be forced to patch howler with this fix for my own use until it's resolved.

I was using this library in an Angular 2 project. I wrapped the functions such as play pause in an Angular service.

So a button click event would go to the Angular service and the service would then call the howler object play function.

When I removed this wrapper and directly called play from howler's object, it fixed the problem on Android.

Ex:

I change to this:

<button (click)="playService.howlerPlayer.play()">Play</button>

playService.howlerPlayer is the howler object.

Instead of:

<button (click)="playService.play()">Play</button>

@swaheed2 Will this work when you enforce html5 mode? (e.g. set html5: true when initializing a Howl).

Howler seems to take different paths depending on where, when and how you're using it. I'm wanting HTML5 to be enforced.

@marcusstenbeck yes I also enforced html5 mode

Note: I've only tested it on Android Nexus 6 Chrome browser and it works

I'll see if I can make a jsbin tomorrow with the error.

Here's a jsbin that will not work on my Android devices.

http://jsbin.com/vutesexihi/1

I am getting this error on Chrome Android. other mobile browsers not tested. It seems to match this Chrome issue : https://bugs.chromium.org/p/chromium/issues/detail?id=178297

I can understand if this behavior is Chrome's fault, but Howler should provide a way to catch/listen/detect this error in some way, so that we can know that the play() call didn't work and adjust the UI accordingly.
I've poked around with try/catch and various event handlers, it doesn't seem detectable currently.

@implicitdef Try removing the setTimeout (not the code within). E.g. make the below change to your howler.js file, and test again. Does it work?

Change this

          setTimeout(function() {
            node.play();

            // Setup the new end timer.
            if (timeout !== Infinity) {
              self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
            }

            if (!internal) {
              self._emit('play', sound._id);
            }
          }, 0);

into this

//          setTimeout(function() {
            node.play();

            // Setup the new end timer.
            if (timeout !== Infinity) {
              self._endTimers[sound._id] = setTimeout(self._ended.bind(self, sound), timeout);
            }

            if (!internal) {
              self._emit('play', sound._id);
            }
//          }, 0);

@marcusstenbeck No, in my case it doesn't change everything.
Note though that, unlike you I think, I _am_ trying to play something without a user gesture (I want to autoplay a sound when the user arrives on a page).

My problem is not that this is restricted, it's more that the restriction is undetectable, forcing me to tweak my code based on the user agent. Maybe I should file a separate issue ?

@implicitdef - It is in the howler documentation that a touch is required to play sounds on certain devices - https://github.com/goldfire/howler.js#mobile-playback

I'm not sure what more Howler can do? Throw a console log error each time a sound is attempted to be played but the browser still has webaudio locked?

They could wrap their play() call in a try catch, and fire a 'playerror' event, for instance, similar to the existing 'loaderror' event.

Oh, yeah. Autoplaying is a different issue than what you have @implicitdef. I'm strictly interested in playing triggered by a user gesture.

Filed a separate issue. Sorry for the noise.

I've created a pull request with the fix that solves it in my testing conditions. #694

694 has now been merged into master and will be included in 2.0.3.

Does anyone still having this issue? I've just upgraded to the latest version (2.0.5) but still having the same problem.

@volkan-umg yup, i got the same on canary 65

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sibelius picture sibelius  路  3Comments

bflora2 picture bflora2  路  4Comments

joshbruce picture joshbruce  路  4Comments

lili21 picture lili21  路  4Comments

Glutch picture Glutch  路  3Comments