scottschiller / SoundManager2

A JavaScript Sound API supporting MP3, MPEG4 and HTML5 audio + RTMP, providing reliable cross-browser/platform audio control in as little as 12 KB. BSD licensed.
http://www.schillmania.com/projects/soundmanager2/
Other
4.98k stars 769 forks source link

Browser autoplay policy error catch #219

Open JSoon opened 6 years ago

JSoon commented 6 years ago

Recently due to more and more browsers begin to implement the media autoplay policy, i found that we can't play the music on our site automatically. After some research i solved this issue, while calling the error event to catch the error.

Maybe need to add a specific error code to it, but i think it's better to add it by you for the better code organization.

Please check it out, thanks.

virmelcruz commented 5 years ago

I'm having same scenario where the onError does not catch the autoplay policy error. + 1 for this.

scottschiller commented 5 years ago

Thanks, sorry for the late follow-up on this - I am going to look at having SM2 return the promise the browser gives you when auto-play type stuff is blocked, so you know that things didn't work and then can hook off of that.

The best thing is not to try to auto-play at all, and then if for whatever reason things are blocked, you can give the user a notice to tap or click something in order to attempt playback again.

scottschiller commented 5 years ago

I like the idea of firing onerror() here too, but there are times when that method can be fired during playback and I want to prototype and tinker with the onerror() approach vs. a new method, or something else entirely for the "playback blocked" case.

lestcape commented 2 years ago

In the meantime you can convert the error in a warning from outside the plugin without touch the code and with the ensure that not any call of the play function will ended in an error. You need to add something like that before you load the plugin or directly after that. What this is doing is injecting code in all the instances of the html5 Audio class, to catch the error and prevent the propagation of it to the console:

(function (window, document, _undefined) {
    "use strict";
    if ((typeof window.Audio !== "undefined") && window.Audio) {
        Audio = (function(Audio) {
            return function(url) {
                var aud = new Audio(url);//...arguments
                aud._original_play = aud.play;
                aud.play = function() {       // overwrite method
                    var promise = this._original_play();
                    if ((promise !== undefined) && promise.catch) {
                        promise['catch'](function(error) {
                            // Autoplay was prevented.
                            // Show a "Play" button so that user can start playback.
                        });
                    }
                    return promise;
                };
                return aud;
            }
        }(Audio));
    }
})(window, document);