Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
swaheed2 opened this issue Aug 30, 2016 · 18 comments

Comments

@swaheed2
Copy link

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?

@marcusstenbeck
Copy link
Contributor

marcusstenbeck commented Dec 21, 2016

@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: 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.

@swaheed2
Copy link
Author

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>

@marcusstenbeck
Copy link
Contributor

@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.

@swaheed2
Copy link
Author

@marcusstenbeck yes I also enforced html5 mode

@swaheed2
Copy link
Author

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

@marcusstenbeck
Copy link
Contributor

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

@marcusstenbeck
Copy link
Contributor

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

http://jsbin.com/vutesexihi/1

@implicitdef
Copy link

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.

@marcusstenbeck
Copy link
Contributor

@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);

@implicitdef
Copy link

@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 ?

@themoonrat
Copy link
Contributor

@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?

@implicitdef
Copy link

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

@marcusstenbeck
Copy link
Contributor

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

@implicitdef
Copy link

Filed a separate issue. Sorry for the noise.

marcusstenbeck added a commit to marcusstenbeck/howler.js that referenced this issue Jan 20, 2017
…l stack

On mobile, the play event needs to be triggered by a user gesture. By setting a timeout the call
stack containing the user tap gesture is lost. Since this was added way back to support something in
Firefox 13 it could most likely be removed without negative impact.

  goldfire#609
@marcusstenbeck
Copy link
Contributor

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

@goldfire
Copy link
Owner

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

@volkan-umg
Copy link

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

@shellka
Copy link

shellka commented Dec 11, 2017

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants